delvh
a4e9474b97
Fixed potentially not saving when using alt f4 and disabled hiding if StatusTrayIcon is not supported Reviewed-on: https://git.kske.dev/zdm/envoy/pulls/65 Reviewed-by: kske <kai@kske.dev> Reviewed-by: DieGurke <maxi@kske.dev>
226 lines
7.2 KiB
Java
226 lines
7.2 KiB
Java
package envoy.client.ui;
|
|
|
|
import java.io.*;
|
|
import java.time.Instant;
|
|
import java.util.concurrent.TimeoutException;
|
|
import java.util.logging.*;
|
|
|
|
import javafx.application.Application;
|
|
import javafx.scene.control.Alert;
|
|
import javafx.scene.control.Alert.AlertType;
|
|
import javafx.stage.Stage;
|
|
|
|
import envoy.client.data.*;
|
|
import envoy.client.helper.ShutdownHelper;
|
|
import envoy.client.net.Client;
|
|
import envoy.client.ui.SceneContext.SceneInfo;
|
|
import envoy.client.ui.controller.LoginScene;
|
|
import envoy.client.util.IconUtil;
|
|
import envoy.data.*;
|
|
import envoy.data.User.UserStatus;
|
|
import envoy.event.*;
|
|
import envoy.exception.EnvoyException;
|
|
import envoy.util.EnvoyLog;
|
|
|
|
/**
|
|
* Handles application startup.
|
|
*
|
|
* @author Kai S. K. Engelbart
|
|
* @author Maximilian Käfer
|
|
* @since Envoy Client v0.1-beta
|
|
*/
|
|
public final class Startup extends Application {
|
|
|
|
/**
|
|
* The version of this client. Used to verify compatibility with the server.
|
|
*
|
|
* @since Envoy Client v0.1-beta
|
|
*/
|
|
public static final String VERSION = "0.2-beta";
|
|
|
|
private static LocalDB localDB;
|
|
|
|
private static final Context context = Context.getInstance();
|
|
private static final Client client = context.getClient();
|
|
private static final ClientConfig config = ClientConfig.getInstance();
|
|
private static final Logger logger = EnvoyLog.getLogger(Startup.class);
|
|
|
|
/**
|
|
* Loads the configuration, initializes the client and the local database and
|
|
* delegates the rest of the startup process to {@link LoginScene}.
|
|
*
|
|
* @since Envoy Client v0.1-beta
|
|
*/
|
|
@Override
|
|
public void start(Stage stage) throws Exception {
|
|
|
|
// Initialize config and logger
|
|
try {
|
|
config.loadAll(Startup.class, "client.properties", getParameters().getRaw().toArray(new String[0]));
|
|
EnvoyLog.initialize(config);
|
|
} catch (final IllegalStateException e) {
|
|
new Alert(AlertType.ERROR, "Error loading configuration values:\n" + e);
|
|
logger.log(Level.SEVERE, "Error loading configuration values: ", e);
|
|
System.exit(1);
|
|
}
|
|
logger.log(Level.INFO, "Envoy starting...");
|
|
|
|
// Initialize the local database
|
|
try {
|
|
final var localDBFile = new File(config.getHomeDirectory(), config.getServer());
|
|
logger.info("Initializing LocalDB at " + localDBFile);
|
|
localDB = new LocalDB(localDBFile);
|
|
} catch (IOException | EnvoyException e) {
|
|
logger.log(Level.SEVERE, "Could not initialize local database: ", e);
|
|
new Alert(AlertType.ERROR, "Could not initialize local database!\n" + e).showAndWait();
|
|
System.exit(1);
|
|
return;
|
|
}
|
|
|
|
// Prepare handshake
|
|
context.setLocalDB(localDB);
|
|
|
|
// Configure stage
|
|
stage.setTitle("Envoy");
|
|
stage.getIcons().add(IconUtil.loadIcon("envoy_logo"));
|
|
|
|
// Create scene context
|
|
final var sceneContext = new SceneContext(stage);
|
|
context.setSceneContext(sceneContext);
|
|
|
|
// Authenticate with token if present
|
|
if (localDB.getAuthToken() != null) {
|
|
logger.info("Attempting authentication with token...");
|
|
localDB.loadUserData();
|
|
if (!performHandshake(
|
|
LoginCredentials.loginWithToken(localDB.getUser().getName(), localDB.getAuthToken(), VERSION, localDB.getLastSync())))
|
|
sceneContext.load(SceneInfo.LOGIN_SCENE);
|
|
} else
|
|
// Load login scene
|
|
sceneContext.load(SceneInfo.LOGIN_SCENE);
|
|
}
|
|
|
|
/**
|
|
* Tries to perform a Handshake with the server.
|
|
*
|
|
* @param credentials the credentials to use for the handshake
|
|
* @return whether the handshake was successful or offline mode could be entered
|
|
* @since Envoy Client v0.2-beta
|
|
*/
|
|
public static boolean performHandshake(LoginCredentials credentials) {
|
|
final var cacheMap = new CacheMap();
|
|
cacheMap.put(Message.class, new Cache<Message>());
|
|
cacheMap.put(GroupMessage.class, new Cache<GroupMessage>());
|
|
cacheMap.put(MessageStatusChange.class, new Cache<MessageStatusChange>());
|
|
cacheMap.put(GroupMessageStatusChange.class, new Cache<GroupMessageStatusChange>());
|
|
try {
|
|
client.performHandshake(credentials, cacheMap);
|
|
if (client.isOnline()) {
|
|
loadChatScene();
|
|
client.initReceiver(localDB, cacheMap);
|
|
return true;
|
|
} else return false;
|
|
} catch (IOException | InterruptedException | TimeoutException e) {
|
|
logger.log(Level.INFO, "Could not connect to server. Entering offline mode...");
|
|
return attemptOfflineMode(credentials.getIdentifier());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Attempts to load {@link envoy.client.ui.controller.ChatScene} in offline mode
|
|
* for a given user.
|
|
*
|
|
* @param identifier the identifier of the user - currently his username
|
|
* @return whether the offline mode could be entered
|
|
* @since Envoy Client v0.2-beta
|
|
*/
|
|
public static boolean attemptOfflineMode(String identifier) {
|
|
try {
|
|
// Try entering offline mode
|
|
final User clientUser = localDB.getUsers().get(identifier);
|
|
if (clientUser == null) throw new EnvoyException("Could not enter offline mode: user name unknown");
|
|
client.setSender(clientUser);
|
|
loadChatScene();
|
|
return true;
|
|
} catch (final Exception e) {
|
|
new Alert(AlertType.ERROR, "Client error: " + e).showAndWait();
|
|
logger.log(Level.SEVERE, "Offline mode could not be loaded: ", e);
|
|
System.exit(1);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Loads the last known time a user has been online.
|
|
*
|
|
* @param identifier the identifier of this user - currently his name
|
|
* @return the last {@code Instant} at which he has been online
|
|
* @since Envoy Client v0.2-beta
|
|
*/
|
|
public static Instant loadLastSync(String identifier) {
|
|
try {
|
|
localDB.setUser(localDB.getUsers().get(identifier));
|
|
localDB.loadUserData();
|
|
} catch (final Exception e) {
|
|
// User storage empty, wrong user name etc. -> default lastSync
|
|
}
|
|
return localDB.getLastSync();
|
|
}
|
|
|
|
private static void loadChatScene() {
|
|
|
|
// Set client user in local database
|
|
localDB.setUser(client.getSender());
|
|
|
|
// Initialize chats in local database
|
|
try {
|
|
localDB.loadUserData();
|
|
} catch (final FileNotFoundException e) {
|
|
// The local database file has not yet been created, probably first login
|
|
} catch (final Exception e) {
|
|
new Alert(AlertType.ERROR, "Error while loading local database: " + e + "\nChats will not be stored locally.").showAndWait();
|
|
logger.log(Level.WARNING, "Could not load local database: ", e);
|
|
}
|
|
|
|
context.initWriteProxy();
|
|
|
|
if (client.isOnline()) context.getWriteProxy().flushCache();
|
|
else
|
|
// Set all contacts to offline mode
|
|
localDB.getChats()
|
|
.stream()
|
|
.map(Chat::getRecipient)
|
|
.filter(User.class::isInstance)
|
|
.map(User.class::cast)
|
|
.forEach(u -> u.setStatus(UserStatus.OFFLINE));
|
|
|
|
final var stage = context.getStage();
|
|
|
|
// Pop LoginScene if present
|
|
if (!context.getSceneContext().isEmpty()) context.getSceneContext().pop();
|
|
|
|
// Load ChatScene
|
|
stage.setMinHeight(400);
|
|
stage.setMinWidth(843);
|
|
context.getSceneContext().load(SceneContext.SceneInfo.CHAT_SCENE);
|
|
stage.centerOnScreen();
|
|
|
|
// Exit or minimize the stage when a close request occurs
|
|
stage.setOnCloseRequest(
|
|
e -> { ShutdownHelper.exit(); if (Settings.getInstance().isHideOnClose() && StatusTrayIcon.isSupported()) e.consume(); });
|
|
|
|
if (StatusTrayIcon.isSupported()) {
|
|
|
|
// Initialize status tray icon
|
|
final var trayIcon = new StatusTrayIcon(stage);
|
|
Settings.getInstance().getItems().get("hideOnClose").setChangeHandler(c -> {
|
|
if ((Boolean) c) trayIcon.show();
|
|
else trayIcon.hide();
|
|
});
|
|
}
|
|
|
|
// Start auto save thread
|
|
localDB.initAutoSave();
|
|
}
|
|
}
|