/*
* LoginController.java - Copyright(c) 2013 Joe Pasqua
* Provided under the MIT License. See the LICENSE file for details.
* Created: Jul 22, 2013
*/
package org.noroomattheinn.visibletesla;
import java.util.concurrent.Callable;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Dialogs;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.scene.image.ImageView;
import org.noroomattheinn.tesla.Result;
import org.noroomattheinn.utils.TrackedObject;
/**
* This controller allows the user to login and logout. The "logged-in" state
* can be monitored by observing the loginCompleteProperty.
*
* After a successful login, this controller also fetches the GUIState and
* VehicleState and caches them in the ac. Other components may use
* these cached values but must understand that they are not updated - they
* represent a snapshot of the values when the user logged in.
*
* TO DO:
* - If there are more than one vehicle associated with the logged-in user,
* allow the user to select the vehicle she's interested in.
*
*
* @author Joe Pasqua <joe at NoRoomAtTheInn dot org>
*/
public class LoginController extends BaseController {
/*------------------------------------------------------------------------------
*
* Constants and Enums
*
*----------------------------------------------------------------------------*/
private static final String RememberMePrefKey = "APP_REMEMBER_ME";
private static final String AuthTokenKey = "APP_AUTH_TOKEN";
private static final String UsernameKey = "APP_USERNAME";
/*------------------------------------------------------------------------------
*
* Observable State
*
*----------------------------------------------------------------------------*/
TrackedObject<Boolean> loggedIn = new TrackedObject<>(false);
/*------------------------------------------------------------------------------
*
* UI Elements
*
*----------------------------------------------------------------------------*/
@FXML private Label loggedInName;
@FXML private Button loginButton;
@FXML private PasswordField passwordField;
@FXML private TextField usernameField;
@FXML private ImageView loggedInImage;
@FXML private Label loggedInStatus;
@FXML private CheckBox rememberMe;
/*------------------------------------------------------------------------------
*
* UI Action Handlers
*
*----------------------------------------------------------------------------*/
@FXML void loginAction(ActionEvent event) {
String username = usernameField.getText().trim();
String password = passwordField.getText();
if (username.isEmpty()) {
loggedInStatus.setText("Please enter a username");
return;
}
attemptLogin(username, password);
}
@FXML void rememberMeHandler(ActionEvent event) {
prefs.storage().putBoolean(RememberMePrefKey, rememberMe.isSelected());
if (!rememberMe.isSelected()) { prefs.storage().remove(AuthTokenKey); }
}
/*------------------------------------------------------------------------------
*
* Methods overridden from BaseController
*
*----------------------------------------------------------------------------*/
@Override protected void fxInitialize() {
App.addTracker(loggedIn, new Runnable() {
@Override public void run() { reflectLoginState(); } });
}
@Override protected void refresh() { }
@Override protected void initializeState() {
Boolean rememberPref = prefs.storage().getBoolean(RememberMePrefKey, false);
rememberMe.setSelected(rememberPref);
String username = rememberPref ? prefs.storage().get(UsernameKey, null) : null;
if (username != null) usernameField.setText(username);
}
@Override protected void activateTab() {
if (loggedIn.get()) return;
String username = usernameField.getText().trim();
if (username.isEmpty()) { loggedIn.set(false); }
else {
showAutoLoginUI();
attemptLogin(username, null);
}
}
/*------------------------------------------------------------------------------
*
* Methods to Reflect the desired state of the UI
*
*----------------------------------------------------------------------------*/
private void showLoginUI(String prompt, String user, boolean loggedIn) {
loggedInStatus.setText(prompt);
loggedInName.setText(user);
loggedInImage.setOpacity(loggedIn ? 1.0 : 0.25);
loginButton.setDisable(loggedIn);
loginButton.setDefaultButton(!loggedIn);
}
private void reflectLoginState() {
if (loggedIn.get()) { showLoginSucceeded(); }
else { showManualLoginUI(); }
}
private void showManualLoginUI() {
showLoginUI("Please enter your credentials", "", false);
usernameField.requestFocus();
}
private void showLoginSucceeded() {
showLoginUI("Logged in as:", app.tesla.getUsername(), true);
}
private void showAutoLoginUI() {
showLoginUI("Attempting Automatic Login", "", false);
}
/*------------------------------------------------------------------------------
*
* Private Utility Methods and Classes
*
*----------------------------------------------------------------------------*/
private void attemptLogin(String username, String password) {
issuer.issueCommand(
new AttemptLogin(username, password), false, progressIndicator, "Attempt Login");
}
private class AttemptLogin implements Callable<Result> {
String username, password;
AttemptLogin(String username, String password) {
this.username = username;
this.password = password;
}
@Override public Result call() {
boolean succeeded;
if (password == null) { // Try auto login
String authToken = prefs.storage().get(AuthTokenKey, null);
succeeded = (authToken == null) ? false :
app.tesla.connectWithToken(username, authToken);
} else { // Login with the specified username and password
succeeded = app.tesla.connect(username, password);
if (!succeeded) {
Platform.runLater(new Runnable() {
@Override public void run() {
Dialogs.showErrorDialog(
app.stage,
"Remember to use your email address as your username",
"Login failed - Please check your credentials",
"Problem logging in");
}
});
} else {
String authToken = app.tesla.getToken();
if (rememberMe.isSelected()) {
prefs.storage().put(AuthTokenKey, authToken);
prefs.storage().put(UsernameKey, username);
}
}
}
loggedIn.set(succeeded);
return succeeded ? Result.Succeeded : Result.Failed;
}
}
}