Merge branch 'develop' into f/new_ui
This commit is contained in:
		
							
								
								
									
										36
									
								
								client/src/main/java/envoy/client/ui/ListViewRefresh.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								client/src/main/java/envoy/client/ui/ListViewRefresh.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
			
		||||
package envoy.client.ui;
 | 
			
		||||
 | 
			
		||||
import javafx.scene.control.ListCell;
 | 
			
		||||
import javafx.scene.control.ListView;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This is a utility class that provides access to a refreshing mechanism for
 | 
			
		||||
 * elements that were added without notifying the underlying {@link ListView}.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Project: <strong>envoy-client</strong><br>
 | 
			
		||||
 * File: <strong>ListViewRefresh.java</strong><br>
 | 
			
		||||
 * Created: <strong>16.07.2020</strong><br>
 | 
			
		||||
 *
 | 
			
		||||
 * @author Leon Hofmeister
 | 
			
		||||
 * @since Envoy Client v0.1-beta
 | 
			
		||||
 */
 | 
			
		||||
public final class ListViewRefresh {
 | 
			
		||||
 | 
			
		||||
	private ListViewRefresh() {}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Deeply refreshes a {@code listview}, meaning it recomputes every single of
 | 
			
		||||
	 * its {@link ListCell}s.
 | 
			
		||||
	 * <p>
 | 
			
		||||
	 * While it does work, it is <b>not the most efficient algorithm</b> possible.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param toRefresh the listView to refresh
 | 
			
		||||
	 * @param <T>       the type of its {@code listcells}
 | 
			
		||||
	 * @since Envoy Client v0.1-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public static <T> void deepRefresh(ListView<T> toRefresh) {
 | 
			
		||||
		final var items = toRefresh.getItems();
 | 
			
		||||
		toRefresh.setItems(null);
 | 
			
		||||
		toRefresh.setItems(items);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -31,9 +31,7 @@ import envoy.client.data.audio.AudioRecorder;
 | 
			
		||||
import envoy.client.event.MessageCreationEvent;
 | 
			
		||||
import envoy.client.net.Client;
 | 
			
		||||
import envoy.client.net.WriteProxy;
 | 
			
		||||
import envoy.client.ui.IconUtil;
 | 
			
		||||
import envoy.client.ui.Restorable;
 | 
			
		||||
import envoy.client.ui.SceneContext;
 | 
			
		||||
import envoy.client.ui.*;
 | 
			
		||||
import envoy.client.ui.listcell.ChatControl;
 | 
			
		||||
import envoy.client.ui.listcell.ListCellFactory;
 | 
			
		||||
import envoy.client.ui.listcell.MessageControl;
 | 
			
		||||
@@ -154,7 +152,7 @@ public final class ChatScene implements Restorable {
 | 
			
		||||
					} catch (final IOException e1) {
 | 
			
		||||
						logger.log(Level.WARNING, "Could not read current chat: ", e1);
 | 
			
		||||
					}
 | 
			
		||||
					Platform.runLater(() -> { messageList.refresh(); scrollToMessageListEnd(); });
 | 
			
		||||
					Platform.runLater(() -> { ListViewRefresh.deepRefresh(messageList); scrollToMessageListEnd(); });
 | 
			
		||||
				} else chat.incrementUnreadAmount();
 | 
			
		||||
				// Moving chat with most recent unreadMessages to the top
 | 
			
		||||
				Platform.runLater(() -> {
 | 
			
		||||
@@ -168,8 +166,9 @@ public final class ChatScene implements Restorable {
 | 
			
		||||
		// Listen to message status changes
 | 
			
		||||
		eventBus.register(MessageStatusChange.class, e -> localDB.getMessage(e.getID()).ifPresent(message -> {
 | 
			
		||||
			message.setStatus(e.get());
 | 
			
		||||
			// Update UI if in current chat
 | 
			
		||||
			if (currentChat != null && message.getSenderID() == currentChat.getRecipient().getID()) Platform.runLater(messageList::refresh);
 | 
			
		||||
			// Update UI if in current chat and the current user was the sender of the
 | 
			
		||||
			// message
 | 
			
		||||
			if (currentChat != null && message.getSenderID() == client.getSender().getID()) Platform.runLater(messageList::refresh);
 | 
			
		||||
		}));
 | 
			
		||||
 | 
			
		||||
		eventBus.register(GroupMessageStatusChange.class, e -> localDB.getMessage(e.getID()).ifPresent(groupMessage -> {
 | 
			
		||||
@@ -186,7 +185,7 @@ public final class ChatScene implements Restorable {
 | 
			
		||||
					.filter(c -> c.getRecipient().getID() == e.getID())
 | 
			
		||||
					.findAny()
 | 
			
		||||
					.map(Chat::getRecipient)
 | 
			
		||||
					.ifPresent(u -> { ((User) u).setStatus(e.get()); Platform.runLater(chatList::refresh); }));
 | 
			
		||||
					.ifPresent(u -> { ((User) u).setStatus(e.get()); Platform.runLater(() -> ListViewRefresh.deepRefresh(chatList)); }));
 | 
			
		||||
 | 
			
		||||
		// Listen to contacts changes
 | 
			
		||||
		eventBus.register(ContactOperation.class, e -> {
 | 
			
		||||
@@ -377,6 +376,7 @@ public final class ChatScene implements Restorable {
 | 
			
		||||
			try {
 | 
			
		||||
				final var fileBytes = Files.readAllBytes(file.toPath());
 | 
			
		||||
				pendingAttachment = new Attachment(fileBytes, type);
 | 
			
		||||
				checkPostConditions(false);
 | 
			
		||||
				// Setting the preview image as image of the attachmentView
 | 
			
		||||
				if (type == AttachmentType.PICTURE)
 | 
			
		||||
					attachmentView.setImage(new Image(new ByteArrayInputStream(fileBytes), DEFAULT_ICON_SIZE, DEFAULT_ICON_SIZE, true, true));
 | 
			
		||||
@@ -435,9 +435,9 @@ public final class ChatScene implements Restorable {
 | 
			
		||||
				|| !settings.isEnterToSend() && e.getCode() == KeyCode.ENTER && e.isControlDown());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private void checkPostConditions(boolean sendKeyPressed) {
 | 
			
		||||
	private void checkPostConditions(boolean postMessage) {
 | 
			
		||||
		if (!postingPermanentlyDisabled) {
 | 
			
		||||
			if (!postButton.isDisabled() && sendKeyPressed) postMessage();
 | 
			
		||||
			if (!postButton.isDisabled() && postMessage) postMessage();
 | 
			
		||||
			postButton.setDisable(messageTextArea.getText().isBlank() && pendingAttachment == null || currentChat == null);
 | 
			
		||||
		} else {
 | 
			
		||||
			final var noMoreMessaging = "Go online to send messages";
 | 
			
		||||
@@ -520,7 +520,7 @@ public final class ChatScene implements Restorable {
 | 
			
		||||
				localDB.getChats().remove(currentChat);
 | 
			
		||||
				localDB.getChats().add(0, currentChat);
 | 
			
		||||
			});
 | 
			
		||||
			messageList.refresh();
 | 
			
		||||
			ListViewRefresh.deepRefresh(messageList);
 | 
			
		||||
			scrollToMessageListEnd();
 | 
			
		||||
 | 
			
		||||
			// Request a new ID generator if all IDs were used
 | 
			
		||||
 
 | 
			
		||||
@@ -118,7 +118,8 @@ public class ContactSearchScene {
 | 
			
		||||
				final var event = new ContactOperation(user, ElementOperation.ADD);
 | 
			
		||||
				// Sends the event to the server
 | 
			
		||||
				eventBus.dispatch(new SendEvent(event));
 | 
			
		||||
				// Updates the UI
 | 
			
		||||
				// Removes the chosen user and updates the UI
 | 
			
		||||
				userList.getItems().remove(user);
 | 
			
		||||
				eventBus.dispatch(event);
 | 
			
		||||
				logger.log(Level.INFO, "Added user " + user);
 | 
			
		||||
			}));
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,8 @@ import envoy.client.ui.ClearableTextField;
 | 
			
		||||
import envoy.client.ui.SceneContext;
 | 
			
		||||
import envoy.client.ui.listcell.ContactControl;
 | 
			
		||||
import envoy.client.ui.listcell.ListCellFactory;
 | 
			
		||||
import envoy.data.Contact;
 | 
			
		||||
import envoy.data.Group;
 | 
			
		||||
import envoy.data.User;
 | 
			
		||||
import envoy.event.EventBus;
 | 
			
		||||
import envoy.event.GroupCreation;
 | 
			
		||||
@@ -50,6 +52,8 @@ public class GroupCreationScene {
 | 
			
		||||
 | 
			
		||||
	private SceneContext sceneContext;
 | 
			
		||||
 | 
			
		||||
	private LocalDB localDB;
 | 
			
		||||
 | 
			
		||||
	private static final EventBus eventBus = EventBus.getInstance();
 | 
			
		||||
 | 
			
		||||
	@FXML
 | 
			
		||||
@@ -66,7 +70,8 @@ public class GroupCreationScene {
 | 
			
		||||
	 * @since Envoy Client v0.1-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public void initializeData(SceneContext sceneContext, LocalDB localDB) {
 | 
			
		||||
		this.sceneContext = sceneContext;
 | 
			
		||||
		this.sceneContext	= sceneContext;
 | 
			
		||||
		this.localDB		= localDB;
 | 
			
		||||
		Platform.runLater(() -> userList.getItems()
 | 
			
		||||
			.addAll(localDB.getChats()
 | 
			
		||||
				.stream()
 | 
			
		||||
@@ -109,14 +114,47 @@ public class GroupCreationScene {
 | 
			
		||||
		if (!Bounds.isValidContactName(name)) {
 | 
			
		||||
			new Alert(AlertType.ERROR, "The entered group name is not valid (" + Bounds.CONTACT_NAME_PATTERN + ")").showAndWait();
 | 
			
		||||
			groupNameField.getTextField().clear();
 | 
			
		||||
		} else if (groupNameAlreadyPresent(name)) {
 | 
			
		||||
			final var alert = new Alert(AlertType.WARNING, "You already have a group with that name.", ButtonType.OK, ButtonType.CANCEL);
 | 
			
		||||
			alert.setTitle("Create Group?");
 | 
			
		||||
			alert.setHeaderText("Proceed?");
 | 
			
		||||
			alert.showAndWait().filter(btn -> btn == ButtonType.OK).ifPresent(btn -> createGroup(name));
 | 
			
		||||
		} else {
 | 
			
		||||
			eventBus.dispatch(new SendEvent(
 | 
			
		||||
					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();
 | 
			
		||||
			sceneContext.pop();
 | 
			
		||||
			createGroup(name);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Creates a new group with the given name and all selected members.<br>
 | 
			
		||||
	 * Additionally pops the scene automatically.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param name the chosen group name
 | 
			
		||||
	 * @since Envoy Client v0.1-beta
 | 
			
		||||
	 */
 | 
			
		||||
	private void createGroup(String name) {
 | 
			
		||||
		eventBus.dispatch(new SendEvent(
 | 
			
		||||
				new GroupCreation(name, userList.getSelectionModel().getSelectedItems().stream().map(User::getID).collect(Collectors.toSet()))));
 | 
			
		||||
		sceneContext.pop();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Returns true if the proposed group name is already present in the users
 | 
			
		||||
	 * {@code LocalDB}.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param newName the chosen group name
 | 
			
		||||
	 * @return true if this name is already present
 | 
			
		||||
	 * @since Envoy Client v0.1-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public boolean groupNameAlreadyPresent(String newName) {
 | 
			
		||||
		return localDB.getChats()
 | 
			
		||||
			.stream()
 | 
			
		||||
			.map(Chat::getRecipient)
 | 
			
		||||
			.filter(Group.class::isInstance)
 | 
			
		||||
			.map(Contact::getName)
 | 
			
		||||
			.anyMatch(newName::equals);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@FXML
 | 
			
		||||
	private void backButtonClicked() { sceneContext.pop(); }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user