Add ContactListCellFactory
- Refactor chatList to userList in ContactSearchScene and GroupCreationScene - Narrow contact searches down to users on a datamodel basis - Refactor ContactSearchRequest and ContactSearchResult to UserSearchRequest and UserSearchResult
This commit is contained in:
		@@ -12,7 +12,7 @@ import envoy.client.event.SendEvent;
 | 
			
		||||
import envoy.data.*;
 | 
			
		||||
import envoy.event.*;
 | 
			
		||||
import envoy.event.contact.ContactOperation;
 | 
			
		||||
import envoy.event.contact.ContactSearchResult;
 | 
			
		||||
import envoy.event.contact.UserSearchResult;
 | 
			
		||||
import envoy.util.EnvoyLog;
 | 
			
		||||
import envoy.util.SerializationUtils;
 | 
			
		||||
 | 
			
		||||
@@ -147,7 +147,7 @@ public class Client implements Closeable {
 | 
			
		||||
		receiver.registerProcessor(NameChange.class, evt -> { localDB.replaceContactName(evt); eventBus.dispatch(evt); });
 | 
			
		||||
 | 
			
		||||
		// Process contact searches
 | 
			
		||||
		receiver.registerProcessor(ContactSearchResult.class, eventBus::dispatch);
 | 
			
		||||
		receiver.registerProcessor(UserSearchResult.class, eventBus::dispatch);
 | 
			
		||||
 | 
			
		||||
		// Process contact operations
 | 
			
		||||
		receiver.registerProcessor(ContactOperation.class, eventBus::dispatch);
 | 
			
		||||
 
 | 
			
		||||
@@ -34,7 +34,7 @@ import envoy.client.net.WriteProxy;
 | 
			
		||||
import envoy.client.ui.IconUtil;
 | 
			
		||||
import envoy.client.ui.Restorable;
 | 
			
		||||
import envoy.client.ui.SceneContext;
 | 
			
		||||
import envoy.client.ui.listcell.ContactListCellFactory;
 | 
			
		||||
import envoy.client.ui.listcell.ChatListCellFactory;
 | 
			
		||||
import envoy.client.ui.listcell.MessageControl;
 | 
			
		||||
import envoy.client.ui.listcell.MessageListCellFactory;
 | 
			
		||||
import envoy.data.*;
 | 
			
		||||
@@ -125,7 +125,7 @@ public final class ChatScene implements Restorable {
 | 
			
		||||
 | 
			
		||||
		// Initialize message and user rendering
 | 
			
		||||
		messageList.setCellFactory(MessageListCellFactory::new);
 | 
			
		||||
		chatList.setCellFactory(ContactListCellFactory::new);
 | 
			
		||||
		chatList.setCellFactory(ChatListCellFactory::new);
 | 
			
		||||
 | 
			
		||||
		settingsButton.setGraphic(new ImageView(IconUtil.loadIconThemeSensitive("settings", 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().add(0, chat);
 | 
			
		||||
					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:
 | 
			
		||||
					localDB.getUsers().put(contact.getName(), contact);
 | 
			
		||||
					Chat chat = contact instanceof User ? new Chat(contact) : new GroupChat(client.getSender(), contact);
 | 
			
		||||
					localDB.getChats().add(chat);
 | 
			
		||||
					Platform.runLater(() -> chatList.getItems().add(chat));
 | 
			
		||||
					break;
 | 
			
		||||
				case REMOVE:
 | 
			
		||||
					localDB.getUsers().remove(contact.getName());
 | 
			
		||||
					localDB.getChats().removeIf(c -> c.getRecipient().getID() == contact.getID());
 | 
			
		||||
					Platform.runLater(() -> chatList.getItems().removeIf(c -> c.getRecipient().getID() == contact.getID()));
 | 
			
		||||
					Platform.runLater(() -> chatList.getItems().removeIf(c -> c.getRecipient().equals(contact)));
 | 
			
		||||
					break;
 | 
			
		||||
			}
 | 
			
		||||
		});
 | 
			
		||||
@@ -233,6 +229,8 @@ public final class ChatScene implements Restorable {
 | 
			
		||||
	 */
 | 
			
		||||
	@FXML
 | 
			
		||||
	private void chatListClicked() {
 | 
			
		||||
		if (chatList.getSelectionModel().isEmpty()) return;
 | 
			
		||||
 | 
			
		||||
		final Contact user = chatList.getSelectionModel().getSelectedItem().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.Logger;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
import javafx.application.Platform;
 | 
			
		||||
import javafx.fxml.FXML;
 | 
			
		||||
@@ -11,22 +10,31 @@ import javafx.scene.control.Alert.AlertType;
 | 
			
		||||
import javafx.scene.control.ButtonType;
 | 
			
		||||
import javafx.scene.control.ListView;
 | 
			
		||||
 | 
			
		||||
import envoy.client.data.Chat;
 | 
			
		||||
import envoy.client.data.LocalDB;
 | 
			
		||||
import envoy.client.event.SendEvent;
 | 
			
		||||
import envoy.client.ui.ClearableTextField;
 | 
			
		||||
import envoy.client.ui.SceneContext;
 | 
			
		||||
import envoy.client.ui.listcell.ContactListCellFactory;
 | 
			
		||||
import envoy.data.User;
 | 
			
		||||
import envoy.event.ElementOperation;
 | 
			
		||||
import envoy.event.EventBus;
 | 
			
		||||
import envoy.event.contact.ContactOperation;
 | 
			
		||||
import envoy.event.contact.ContactSearchRequest;
 | 
			
		||||
import envoy.event.contact.ContactSearchResult;
 | 
			
		||||
import envoy.event.contact.UserSearchRequest;
 | 
			
		||||
import envoy.event.contact.UserSearchResult;
 | 
			
		||||
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>
 | 
			
		||||
 * File: <strong>ContactSearchSceneController.java</strong><br>
 | 
			
		||||
 * File: <strong>ContactSearchScene.java</strong><br>
 | 
			
		||||
 * Created: <strong>07.06.2020</strong><br>
 | 
			
		||||
 *
 | 
			
		||||
 * @author Leon Hofmeister
 | 
			
		||||
@@ -38,7 +46,7 @@ public class ContactSearchScene {
 | 
			
		||||
	private ClearableTextField searchBar;
 | 
			
		||||
 | 
			
		||||
	@FXML
 | 
			
		||||
	private ListView<Chat> chatList;
 | 
			
		||||
	private ListView<User> userList;
 | 
			
		||||
 | 
			
		||||
	private SceneContext sceneContext;
 | 
			
		||||
 | 
			
		||||
@@ -59,12 +67,12 @@ public class ContactSearchScene {
 | 
			
		||||
 | 
			
		||||
	@FXML
 | 
			
		||||
	private void initialize() {
 | 
			
		||||
		chatList.setCellFactory(ContactListCellFactory::new);
 | 
			
		||||
		searchBar.setClearButtonListener(e -> { searchBar.getTextField().clear(); chatList.getItems().clear(); });
 | 
			
		||||
		eventBus.register(ContactSearchResult.class,
 | 
			
		||||
		userList.setCellFactory(new ContactListCellFactory<>());
 | 
			
		||||
		searchBar.setClearButtonListener(e -> { searchBar.getTextField().clear(); userList.getItems().clear(); });
 | 
			
		||||
		eventBus.register(UserSearchResult.class,
 | 
			
		||||
				response -> Platform.runLater(() -> {
 | 
			
		||||
					chatList.getItems().clear();
 | 
			
		||||
					chatList.getItems().addAll(response.get().stream().map(Chat::new).collect(Collectors.toList()));
 | 
			
		||||
					userList.getItems().clear();
 | 
			
		||||
					userList.getItems().addAll(response.get());
 | 
			
		||||
				}));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -76,8 +84,8 @@ public class ContactSearchScene {
 | 
			
		||||
	@FXML
 | 
			
		||||
	private void sendRequest() {
 | 
			
		||||
		final var text = searchBar.getTextField().getText().strip();
 | 
			
		||||
		if (!text.isBlank()) eventBus.dispatch(new SendEvent(new ContactSearchRequest(text)));
 | 
			
		||||
		else chatList.getItems().clear();
 | 
			
		||||
		if (!text.isBlank()) eventBus.dispatch(new SendEvent(new UserSearchRequest(text)));
 | 
			
		||||
		else userList.getItems().clear();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@@ -89,7 +97,7 @@ public class ContactSearchScene {
 | 
			
		||||
	@FXML
 | 
			
		||||
	private void clear() {
 | 
			
		||||
		searchBar.getTextField().setText(null);
 | 
			
		||||
		chatList.getItems().clear();
 | 
			
		||||
		userList.getItems().clear();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@@ -100,21 +108,21 @@ public class ContactSearchScene {
 | 
			
		||||
	 */
 | 
			
		||||
	@FXML
 | 
			
		||||
	private void chatListClicked() {
 | 
			
		||||
		final var chat = chatList.getSelectionModel().getSelectedItem();
 | 
			
		||||
		if (chat != null) {
 | 
			
		||||
		final var user = userList.getSelectionModel().getSelectedItem();
 | 
			
		||||
		if (user != null) {
 | 
			
		||||
			final var alert = new Alert(AlertType.CONFIRMATION);
 | 
			
		||||
			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
 | 
			
		||||
			// it could be proven that the creation of this dialog wrapped in
 | 
			
		||||
			// Platform.runLater is less error-prone than without it
 | 
			
		||||
			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
 | 
			
		||||
				eventBus.dispatch(new SendEvent(event));
 | 
			
		||||
				// Updates the UI
 | 
			
		||||
				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;
 | 
			
		||||
 | 
			
		||||
import static java.util.function.Predicate.not;
 | 
			
		||||
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
import javafx.application.Platform;
 | 
			
		||||
@@ -13,14 +15,22 @@ import envoy.client.event.SendEvent;
 | 
			
		||||
import envoy.client.ui.ClearableTextField;
 | 
			
		||||
import envoy.client.ui.SceneContext;
 | 
			
		||||
import envoy.client.ui.listcell.ContactListCellFactory;
 | 
			
		||||
import envoy.data.Group;
 | 
			
		||||
import envoy.data.User;
 | 
			
		||||
import envoy.event.EventBus;
 | 
			
		||||
import envoy.event.GroupCreation;
 | 
			
		||||
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>
 | 
			
		||||
 * File: <strong>ContactSearchSceneController.java</strong><br>
 | 
			
		||||
 * File: <strong>GroupCreationScene.java</strong><br>
 | 
			
		||||
 * Created: <strong>07.06.2020</strong><br>
 | 
			
		||||
 *
 | 
			
		||||
 * @author Maximilian Käfer
 | 
			
		||||
@@ -35,7 +45,7 @@ public class GroupCreationScene {
 | 
			
		||||
	private ClearableTextField groupNameField;
 | 
			
		||||
 | 
			
		||||
	@FXML
 | 
			
		||||
	private ListView<Chat> chatList;
 | 
			
		||||
	private ListView<User> userList;
 | 
			
		||||
 | 
			
		||||
	private SceneContext sceneContext;
 | 
			
		||||
 | 
			
		||||
@@ -43,8 +53,8 @@ public class GroupCreationScene {
 | 
			
		||||
 | 
			
		||||
	@FXML
 | 
			
		||||
	private void initialize() {
 | 
			
		||||
		chatList.setCellFactory(ContactListCellFactory::new);
 | 
			
		||||
		chatList.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
 | 
			
		||||
		userList.setCellFactory(new ContactListCellFactory<>());
 | 
			
		||||
		userList.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
 | 
			
		||||
		groupNameField.setClearButtonListener(e -> { groupNameField.getTextField().clear(); createButton.setDisable(true); });
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -56,11 +66,13 @@ public class GroupCreationScene {
 | 
			
		||||
	 */
 | 
			
		||||
	public void initializeData(SceneContext sceneContext, LocalDB localDB) {
 | 
			
		||||
		this.sceneContext = sceneContext;
 | 
			
		||||
		Platform.runLater(() -> chatList.getItems()
 | 
			
		||||
		Platform.runLater(() -> userList.getItems()
 | 
			
		||||
			.addAll(localDB.getChats()
 | 
			
		||||
				.stream()
 | 
			
		||||
				.filter(c -> !(c.getRecipient() instanceof Group))
 | 
			
		||||
				.filter(c -> c.getRecipient().getID() != localDB.getUser().getID())
 | 
			
		||||
				.map(Chat::getRecipient)
 | 
			
		||||
				.filter(User.class::isInstance)
 | 
			
		||||
				.filter(not(localDB.getUser()::equals))
 | 
			
		||||
				.map(User.class::cast)
 | 
			
		||||
				.collect(Collectors.toList())));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -71,12 +83,12 @@ public class GroupCreationScene {
 | 
			
		||||
	 */
 | 
			
		||||
	@FXML
 | 
			
		||||
	private void chatListClicked() {
 | 
			
		||||
		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
 | 
			
		||||
	 * present in the textfield.
 | 
			
		||||
	 * present in the text field.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @since Envoy Client v0.1-beta
 | 
			
		||||
	 */
 | 
			
		||||
@@ -97,8 +109,8 @@ public class GroupCreationScene {
 | 
			
		||||
			new Alert(AlertType.ERROR, "The entered group name is not valid (" + Bounds.CONTACT_NAME_PATTERN + ")").showAndWait();
 | 
			
		||||
			groupNameField.getTextField().clear();
 | 
			
		||||
		} else {
 | 
			
		||||
			eventBus.dispatch(new SendEvent(new GroupCreation(name,
 | 
			
		||||
					chatList.getSelectionModel().getSelectedItems().stream().map(c -> c.getRecipient().getID()).collect(Collectors.toSet()))));
 | 
			
		||||
			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();
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,44 @@
 | 
			
		||||
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>ChatListCellFactory.java</strong><br>
 | 
			
		||||
 * Created: <strong>28.03.2020</strong><br>
 | 
			
		||||
 *
 | 
			
		||||
 * @author Kai S. K. Engelbart
 | 
			
		||||
 * @since Envoy Client v0.1-beta
 | 
			
		||||
 */
 | 
			
		||||
public class ChatListCellFactory 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 ChatListCellFactory(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);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -28,7 +28,6 @@ public class ContactControl extends VBox {
 | 
			
		||||
 | 
			
		||||
		// Name label
 | 
			
		||||
		final var nameLabel = new Label(contact.getName());
 | 
			
		||||
		nameLabel.setWrapText(true);
 | 
			
		||||
		getChildren().add(nameLabel);
 | 
			
		||||
 | 
			
		||||
		// Online status (user) or member count (group)
 | 
			
		||||
 
 | 
			
		||||
@@ -2,43 +2,51 @@ package envoy.client.ui.listcell;
 | 
			
		||||
 | 
			
		||||
import javafx.scene.control.ListCell;
 | 
			
		||||
import javafx.scene.control.ListView;
 | 
			
		||||
import javafx.util.Callback;
 | 
			
		||||
 | 
			
		||||
import envoy.client.data.Chat;
 | 
			
		||||
import envoy.data.Contact;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Project: <strong>envoy-client</strong><br>
 | 
			
		||||
 * File: <strong>UserListCell.java</strong><br>
 | 
			
		||||
 * Created: <strong>28.03.2020</strong><br>
 | 
			
		||||
 * File: <strong>ContactListCellFactory.java</strong><br>
 | 
			
		||||
 * Created: <strong>13.07.2020</strong><br>
 | 
			
		||||
 *
 | 
			
		||||
 * @author Kai S. K. Engelbart
 | 
			
		||||
 * @param <T> the type of contact to display
 | 
			
		||||
 * @since Envoy Client v0.1-beta
 | 
			
		||||
 */
 | 
			
		||||
public class ContactListCellFactory extends ListCell<Chat> {
 | 
			
		||||
 | 
			
		||||
	private final ListView<Chat> listView;
 | 
			
		||||
public class ContactListCellFactory<T extends Contact> implements Callback<ListView<T>, ListCell<T>> {
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @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.
 | 
			
		||||
	 * Wraps a the {@link ContactControl} inside a list cell.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param <T> the type of contact to display
 | 
			
		||||
	 * @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);
 | 
			
		||||
	public static final class ContactListCell<T extends Contact> extends ListCell<T> {
 | 
			
		||||
 | 
			
		||||
		private final ListView<T> listView;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @param listView the list view containing this list cell
 | 
			
		||||
		 * @since Envoy Client v0.1-beta
 | 
			
		||||
		 */
 | 
			
		||||
		public ContactListCell(ListView<T> listView) { this.listView = listView; }
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		protected void updateItem(T contact, boolean empty) {
 | 
			
		||||
			super.updateItem(contact, empty);
 | 
			
		||||
			if (empty || contact == null) {
 | 
			
		||||
				setText(null);
 | 
			
		||||
				setGraphic(null);
 | 
			
		||||
			} else {
 | 
			
		||||
				final var control = new ContactControl(contact);
 | 
			
		||||
				prefWidthProperty().bind(listView.widthProperty().subtract(40));
 | 
			
		||||
				setGraphic(control);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public ListCell<T> call(ListView<T> listView) { return new ContactListCell<>(listView); }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user