Add Ability to Change the User Status Freely #90
@ -297,6 +297,7 @@ public final class ChatScene implements EventListener, Restorable {
|
||||
chatList.setCellFactory(new ListCellFactory<>(ChatControl::new));
|
||||
messageList.setCellFactory(MessageListCell::new);
|
||||
// TODO: cache image
|
||||
if (currentChat != null)
|
||||
if (currentChat.getRecipient() instanceof User) recipientProfilePic.setImage(IconUtil.loadIconThemeSensitive("user_icon", 43));
|
||||
else recipientProfilePic.setImage(IconUtil.loadIconThemeSensitive("group_icon", 43));
|
||||
}
|
||||
|
@ -5,8 +5,6 @@ import javafx.scene.control.*;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.stage.DirectoryChooser;
|
||||
|
||||
import envoy.client.data.Context;
|
||||
|
||||
/**
|
||||
* Displays options for downloading {@link envoy.data.Attachment}s.
|
||||
*
|
||||
@ -47,7 +45,7 @@ public final class DownloadSettingsPane extends SettingsPane {
|
||||
final var directoryChooser = new DirectoryChooser();
|
||||
directoryChooser.setTitle("Select the directory where attachments should be saved to");
|
||||
directoryChooser.setInitialDirectory(settings.getDownloadLocation());
|
||||
final var selectedDirectory = directoryChooser.showDialog(Context.getInstance().getSceneContext().getStage());
|
||||
final var selectedDirectory = directoryChooser.showDialog(context.getSceneContext().getStage());
|
||||
|
||||
if (selectedDirectory != null) {
|
||||
currentPath.setText(selectedDirectory.getAbsolutePath());
|
||||
|
@ -7,6 +7,7 @@ import envoy.client.event.ThemeChangeEvent;
|
||||
import envoy.client.helper.ShutdownHelper;
|
||||
import envoy.client.ui.StatusTrayIcon;
|
||||
import envoy.data.User.UserStatus;
|
||||
import envoy.event.UserStatusChange;
|
||||
|
||||
import dev.kske.eventbus.EventBus;
|
||||
|
||||
@ -55,13 +56,23 @@ public final class GeneralSettingsPane extends SettingsPane {
|
||||
combobox.setOnAction(e -> { settings.setCurrentTheme(combobox.getValue()); EventBus.getInstance().dispatch(new ThemeChangeEvent()); });
|
||||
getChildren().add(combobox);
|
||||
|
||||
if (context.getClient().isOnline()) {
|
||||
final var statusComboBox = new ComboBox<UserStatus>();
|
||||
statusComboBox.getItems().setAll(UserStatus.values());
|
||||
statusComboBox.setValue(UserStatus.ONLINE);
|
||||
statusComboBox.setValue(context.getLocalDB().getUser().getStatus());
|
||||
statusComboBox.setTooltip(new Tooltip("Change your current status"));
|
||||
// TODO add action when value is changed
|
||||
statusComboBox.setOnAction(e -> {});
|
||||
statusComboBox.setOnAction(e -> {
|
||||
|
||||
final var status = statusComboBox.getValue();
|
||||
if (status == null) return;
|
||||
else {
|
||||
final var user = context.getLocalDB().getUser();
|
||||
user.setStatus(status);
|
||||
// TODO update status in ChatScene
|
||||
context.getClient().send(new UserStatusChange(user.getID(), status));
|
||||
}
|
||||
});
|
||||
getChildren().add(statusComboBox);
|
||||
}
|
||||
|
||||
final var logoutButton = new Button("Logout");
|
||||
logoutButton.setOnAction(e -> ShutdownHelper.logout());
|
||||
|
@ -5,7 +5,6 @@ import javafx.scene.control.*;
|
||||
import javafx.scene.layout.*;
|
||||
import javafx.scene.paint.Color;
|
||||
|
||||
import envoy.client.data.Context;
|
||||
import envoy.client.net.Client;
|
||||
|
||||
/**
|
||||
@ -20,7 +19,7 @@ import envoy.client.net.Client;
|
||||
*/
|
||||
public abstract class OnlineOnlySettingsPane extends SettingsPane {
|
||||
|
||||
protected final Client client = Context.getInstance().getClient();
|
||||
protected final Client client = context.getClient();
|
||||
|
||||
private final Tooltip beOnlineReminder = new Tooltip("You need to be online to modify your account.");
|
||||
|
||||
|
@ -2,7 +2,7 @@ package envoy.client.ui.settings;
|
||||
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
import envoy.client.data.Settings;
|
||||
import envoy.client.data.*;
|
||||
|
||||
/**
|
||||
* @author Kai S. K. Engelbart
|
||||
@ -13,6 +13,7 @@ public abstract class SettingsPane extends VBox {
|
||||
protected String title;
|
||||
|
||||
protected static final Settings settings = Settings.getInstance();
|
||||
protected static final Context context = Context.getInstance();
|
||||
|
||||
protected SettingsPane(String title) { this.title = title; }
|
||||
|
||||
|
@ -14,7 +14,6 @@ import javafx.scene.input.InputEvent;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.stage.FileChooser;
|
||||
|
||||
import envoy.client.data.Context;
|
||||
import envoy.client.ui.control.ProfilePicImageView;
|
||||
import envoy.client.util.IconUtil;
|
||||
import envoy.event.*;
|
||||
@ -66,7 +65,7 @@ public final class UserSettingsPane extends OnlineOnlySettingsPane {
|
||||
pictureChooser.setInitialDirectory(new File(System.getProperty("user.home")));
|
||||
pictureChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("Pictures", "*.png", "*.jpg", "*.bmp", "*.gif"));
|
||||
|
||||
final var file = pictureChooser.showOpenDialog(Context.getInstance().getSceneContext().getStage());
|
||||
final var file = pictureChooser.showOpenDialog(context.getSceneContext().getStage());
|
||||
|
||||
if (file != null) {
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
-fx-background-radius: 15.0px;
|
||||
}
|
||||
|
||||
.list-cell:selected, .menu-item:hover {
|
||||
.list-cell:selected, .menu-item:hover, .combo-box-popup .list-view .list-cell:selected {
|
||||
-fx-background-color: #454c4f;
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
-fx-background-color: lightgray;
|
||||
}
|
||||
|
||||
#message-list, .text-field, .password-field, .tooltip, .pane, .pane .content, .vbox, .titled-pane > .title, .titled-pane > *.content, .context-menu, .menu-item, #quick-select-list {
|
||||
#message-list, .text-field, .password-field, .tooltip, .pane, .pane .content, .vbox, .titled-pane > .title, .titled-pane > *.content, .context-menu, .menu-item, .combo-box-popup .list-view .list-cell, #quick-select-list {
|
||||
-fx-background-color: #222222;
|
||||
}
|
||||
|
||||
|
@ -22,14 +22,14 @@ public final class ConnectionManager implements ISocketIdListener {
|
||||
*
|
||||
* @since Envoy Server Standalone v0.1-alpha
|
||||
*/
|
||||
private Set<Long> pendingSockets = new HashSet<>();
|
||||
private final Set<Long> pendingSockets = new HashSet<>();
|
||||
|
||||
/**
|
||||
* Contains all socket IDs that have acquired a user ID as keys to these IDs.
|
||||
*
|
||||
* @since Envoy Server Standalone v0.1-alpha
|
||||
*/
|
||||
private Map<Long, Long> sockets = new HashMap<>();
|
||||
private final Map<Long, Long> sockets = new HashMap<>();
|
||||
|
||||
private static ConnectionManager connectionManager = new ConnectionManager();
|
||||
|
||||
@ -44,11 +44,11 @@ public final class ConnectionManager implements ISocketIdListener {
|
||||
@Override
|
||||
public void socketCancelled(long socketID) {
|
||||
if (!pendingSockets.remove(socketID)) {
|
||||
|
||||
// Notify contacts of this users offline-going
|
||||
envoy.server.data.User user = PersistenceManager.getInstance().getUserByID(getUserIDBySocketID(socketID));
|
||||
user.setStatus(UserStatus.OFFLINE);
|
||||
final envoy.server.data.User user = PersistenceManager.getInstance().getUserByID(getUserIDBySocketID(socketID));
|
||||
user.setLastSeen(Instant.now());
|
||||
UserStatusChangeProcessor.updateUserStatus(user);
|
||||
UserStatusChangeProcessor.updateUserStatus(user, UserStatus.OFFLINE);
|
||||
|
||||
// Remove the socket
|
||||
sockets.entrySet().removeIf(e -> e.getValue() == socketID);
|
||||
|
@ -46,8 +46,7 @@ public final class LoginCredentialProcessor implements ObjectProcessor<LoginCred
|
||||
|
||||
// Acquire a user object (or reject the handshake if that's impossible)
|
||||
User user = null;
|
||||
if (!credentials.isRegistration()) {
|
||||
try {
|
||||
if (!credentials.isRegistration()) try {
|
||||
user = persistenceManager.getUserByName(credentials.getIdentifier());
|
||||
|
||||
// Check if the user is already online
|
||||
@ -67,7 +66,7 @@ public final class LoginCredentialProcessor implements ObjectProcessor<LoginCred
|
||||
writeProxy.write(socketID, new HandshakeRejection(INVALID_TOKEN));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
} else
|
||||
|
||||
// Check the password hash
|
||||
if (!PasswordUtil.validate(credentials.getPassword(), user.getPasswordHash())) {
|
||||
@ -75,13 +74,12 @@ public final class LoginCredentialProcessor implements ObjectProcessor<LoginCred
|
||||
writeProxy.write(socketID, new HandshakeRejection(WRONG_PASSWORD_OR_USER));
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (NoResultException e) {
|
||||
} catch (final NoResultException e) {
|
||||
logger.info("The requested user does not exist.");
|
||||
writeProxy.write(socketID, new HandshakeRejection(WRONG_PASSWORD_OR_USER));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
else {
|
||||
|
||||
// Validate user name
|
||||
if (!Bounds.isValidContactName(credentials.getIdentifier())) {
|
||||
@ -98,7 +96,7 @@ public final class LoginCredentialProcessor implements ObjectProcessor<LoginCred
|
||||
logger.info("The requested user already exists.");
|
||||
writeProxy.write(socketID, new HandshakeRejection(USERNAME_TAKEN));
|
||||
return;
|
||||
} catch (NoResultException e) {
|
||||
} catch (final NoResultException e) {
|
||||
// Creation of a new user
|
||||
user = new User();
|
||||
user.setName(credentials.getIdentifier());
|
||||
@ -115,18 +113,17 @@ public final class LoginCredentialProcessor implements ObjectProcessor<LoginCred
|
||||
connectionManager.registerUser(user.getID(), socketID);
|
||||
|
||||
// Change status and notify contacts about it
|
||||
user.setStatus(ONLINE);
|
||||
UserStatusChangeProcessor.updateUserStatus(user);
|
||||
UserStatusChangeProcessor.updateUserStatus(user, ONLINE);
|
||||
|
||||
// Process token request
|
||||
if (credentials.requestToken()) {
|
||||
String token;
|
||||
|
||||
if (user.getAuthToken() != null && user.getAuthTokenExpiration().isAfter(Instant.now())) {
|
||||
if (user.getAuthToken() != null && user.getAuthTokenExpiration().isAfter(Instant.now()))
|
||||
mpk marked this conversation as resolved
mpk
commented
Are you sure all of the code in the body of this if statement gets executed if you remove the curly brackets? Are you sure all of the code in the body of this if statement gets executed if you remove the curly brackets?
delvh
commented
Was my formatter, so I'd guess so. Otherwise blame Eclipse. Was my formatter, so I'd guess so. Otherwise blame Eclipse.
Same for below.
delvh
commented
And yes, it's only one statement, so why shouldn't it? And yes, it's only one statement, so why shouldn't it?
mpk
commented
Because of the comment but I guess it does not count Because of the comment but I guess it does not count
|
||||
|
||||
// Reuse existing token and delay expiration date
|
||||
token = user.getAuthToken();
|
||||
} else {
|
||||
else {
|
||||
|
||||
// Generate new token
|
||||
token = AuthTokenGenerator.nextToken();
|
||||
@ -141,13 +138,13 @@ public final class LoginCredentialProcessor implements ObjectProcessor<LoginCred
|
||||
pendingMessages.removeIf(GroupMessage.class::isInstance);
|
||||
logger.fine("Sending " + pendingMessages.size() + " pending messages to " + user + "...");
|
||||
|
||||
for (var msg : pendingMessages) {
|
||||
for (final var msg : pendingMessages) {
|
||||
final var msgCommon = msg.toCommon();
|
||||
if (msg.getCreationDate().isAfter(credentials.getLastSync())) {
|
||||
if (msg.getCreationDate().isAfter(credentials.getLastSync()))
|
||||
mpk marked this conversation as resolved
mpk
commented
same as above same as above
delvh
commented
Still only one statement. Still only one statement.
|
||||
|
||||
// Sync without side effects
|
||||
writeProxy.write(socketID, msgCommon);
|
||||
} else if (msg.getStatus() == SENT) {
|
||||
else if (msg.getStatus() == SENT) {
|
||||
|
||||
// Send the message
|
||||
writeProxy.write(socketID, msgCommon);
|
||||
@ -162,10 +159,10 @@ public final class LoginCredentialProcessor implements ObjectProcessor<LoginCred
|
||||
} else writeProxy.write(socketID, new MessageStatusChange(msgCommon));
|
||||
}
|
||||
|
||||
List<GroupMessage> pendingGroupMessages = PersistenceManager.getInstance().getPendingGroupMessages(user, credentials.getLastSync());
|
||||
final List<GroupMessage> pendingGroupMessages = PersistenceManager.getInstance().getPendingGroupMessages(user, credentials.getLastSync());
|
||||
logger.fine("Sending " + pendingGroupMessages.size() + " pending group messages to " + user + "...");
|
||||
|
||||
for (var gmsg : pendingGroupMessages) {
|
||||
for (final var gmsg : pendingGroupMessages) {
|
||||
final var gmsgCommon = gmsg.toCommon();
|
||||
|
||||
// Deliver the message to the user if he hasn't received it yet
|
||||
@ -189,20 +186,18 @@ public final class LoginCredentialProcessor implements ObjectProcessor<LoginCred
|
||||
}
|
||||
|
||||
PersistenceManager.getInstance().updateMessage(gmsg);
|
||||
} else {
|
||||
} else
|
||||
|
||||
// Just send the message without updating if it was received in the past
|
||||
writeProxy.write(socketID, gmsgCommon);
|
||||
}
|
||||
} else {
|
||||
|
||||
// Sending group message status changes
|
||||
if (gmsg.getStatus() == SENT && gmsg.getLastStatusChangeDate().isAfter(gmsg.getCreationDate())
|
||||
|| gmsg.getStatus() == RECEIVED && gmsg.getLastStatusChangeDate().isAfter(gmsg.getReceivedDate())) {
|
||||
|| gmsg.getStatus() == RECEIVED && gmsg.getLastStatusChangeDate().isAfter(gmsg.getReceivedDate()))
|
||||
mpk marked this conversation as resolved
mpk
commented
same as above same as above
delvh
commented
Still only one statement Still only one statement
|
||||
gmsg.getMemberMessageStatus()
|
||||
.forEach((memberID, memberStatus) -> writeProxy.write(socketID,
|
||||
new GroupMessageStatusChange(gmsg.getID(), memberStatus, gmsg.getLastStatusChangeDate(), memberID)));
|
||||
}
|
||||
|
||||
// Deliver just a status change instead of the whole message
|
||||
if (gmsg.getStatus() == RECEIVED && user.getLastSeen().isBefore(gmsg.getReceivedDate())
|
||||
|
@ -28,18 +28,20 @@ public final class UserStatusChangeProcessor implements ObjectProcessor<UserStat
|
||||
logger.warning("Received an unnecessary UserStatusChange");
|
||||
return;
|
||||
}
|
||||
updateUserStatus(input);
|
||||
updateUserStatus(persistenceManager.getUserByID(input.getID()), input.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link UserStatus} for a given user. Both offline contacts and
|
||||
* currently online contacts are notified.
|
||||
*
|
||||
* @param user the {@link UserStatusChange} that signals the change
|
||||
* @param user the user whose status has changed
|
||||
* @param newStatus the new status of that user
|
||||
* @since Envoy Server Standalone v0.1-alpha
|
||||
*/
|
||||
|
||||
public static void updateUserStatus(User user) {
|
||||
public static void updateUserStatus(User user, UserStatus newStatus) {
|
||||
user.setStatus(newStatus);
|
||||
|
||||
// Handling for newly logged in clients
|
||||
persistenceManager.updateContact(user);
|
||||
@ -48,12 +50,6 @@ public final class UserStatusChangeProcessor implements ObjectProcessor<UserStat
|
||||
writeProxy.writeToOnlineContacts(user.getContacts(), new UserStatusChange(user.getID(), user.getStatus()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param evt the {@link UserStatusChange}
|
||||
* @since Envoy Server Standalone v0.1-alpha
|
||||
*/
|
||||
public static void updateUserStatus(UserStatusChange evt) { updateUserStatus(persistenceManager.getUserByID(evt.getID())); }
|
||||
|
||||
/**
|
||||
* This method is only called by the LoginCredentialProcessor because every
|
||||
* user needs to login (open a socket) before changing his status.
|
||||
|
Reference in New Issue
Block a user
How is this possible?
Artifact from when I called it using the selectionModel before stumbling upon this method.
Yes, agreed, their Javadoc doesn't mention anything about it,so I'll remove it.