UI wiring

This commit is contained in:
Atlante45 2016-07-22 19:48:52 -07:00
parent 205df0cf51
commit f0ff975248
15 changed files with 394 additions and 125 deletions

View file

@ -33,34 +33,13 @@ ModalWindow {
property string title: ""
property int titleWidth: 0
Component {
id: signInBody
SignInBody {}
}
Component {
id: welcomeBody
WelcomeBody {}
}
LoginDialog {
id: loginDialog
Loader {
id: bodyLoader
anchors.fill: parent
sourceComponent: signInBody
}
Connections {
target: loginDialog
onHandleLoginCompleted: {
console.log("Login Succeeded")
bodyLoader.sourceComponent = welcomeBody
bodyLoader.active = true
}
onHandleLoginFailed: {
console.log("Login Failed")
}
source: loginDialog.isSteamRunning() ? "LoginDialog/SignInBody.qml" : "LoginDialog/LinkAccountBody.qml"
}
}

View file

@ -54,6 +54,8 @@ Item {
text: qsTr("Create your profile")
color: hifi.buttons.blue
onClicked: loginDialog.createAccountFromStream()
}
Button {
@ -83,6 +85,15 @@ Item {
lineHeight: 2
lineHeightMode: Text.ProportionalHeight
horizontalAlignment: Text.AlignHCenter
MouseArea {
anchors.fill: parent
onClicked: {
bodyLoader.source = "LinkAccountBody.qml"
bodyLoader.item.width = root.pane.width
bodyLoader.item.height = root.pane.height
}
}
}
Component.onCompleted: {
@ -90,4 +101,30 @@ Item {
root.iconText = "<"
d.resize();
}
Connections {
target: loginDialog
onHandleCreateCompleted: {
console.log("Create Succeeded")
loginDialog.loginThroughSteam()
}
onHandleCreateFailed: {
console.log("Create Failed: " + error)
bodyLoader.source = "UsernameCollisionBody.qml"
bodyLoader.item.width = root.pane.width
bodyLoader.item.height = root.pane.height
}
onHandleLoginCompleted: {
console.log("Login Succeeded")
bodyLoader.setSource("WelcomeBody.qml", { "welcomeBack" : false })
bodyLoader.item.width = root.pane.width
bodyLoader.item.height = root.pane.height
}
onHandleLoginFailed: {
console.log("Login Failed")
}
}
}

View file

@ -17,10 +17,10 @@ import "../styles-uit"
Item {
id: emailSentBody
clip: true
width: pane.width
height: pane.height
width: root.pane.width
height: root.pane.height
property string email: "clement@highfidelity.com"
property string email: ""
QtObject {
id: d

View file

@ -19,10 +19,14 @@ import "../styles-uit"
Item {
id: linkAccountBody
clip: true
width: pane.width
height: pane.height
width: root.pane.width
height: root.pane.height
property bool existingEmail: true
property bool existingEmail: false
function login() {
loginDialog.login(usernameField.text, passwordField.text)
}
QtObject {
id: d
@ -64,7 +68,7 @@ Item {
Column {
id: form
anchors {
top: mainTextContainer.bottom
top: mainTextContainer.visible ? mainTextContainer.bottom : parent.top
left: parent.left
margins: 0
topMargin: 2 * hifi.dimensions.contentSpacing.y
@ -96,6 +100,15 @@ Item {
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
MouseArea {
anchors.fill: parent
onClicked: {
bodyLoader.source = "RecoverPasswordBody.qml"
bodyLoader.item.width = root.pane.width
bodyLoader.item.height = root.pane.height
}
}
}
}
Row {
@ -124,6 +137,15 @@ Item {
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
MouseArea {
anchors.fill: parent
onClicked: {
bodyLoader.source = "RecoverPasswordBody.qml"
bodyLoader.item.width = root.pane.width
bodyLoader.item.height = root.pane.height
}
}
}
}
@ -141,11 +163,14 @@ Item {
onHeightChanged: d.resize(); onWidthChanged: d.resize();
Button {
id: linkAccountButton
anchors.verticalCenter: parent.verticalCenter
width: 200
text: qsTr("Link Account")
text: qsTr(loginDialog.isSteamRunning() ? "Link Account" : "Login")
color: hifi.buttons.blue
onClicked: linkAccountBody.login()
}
Button {
@ -161,5 +186,51 @@ Item {
root.title = qsTr("Sign Into High Fidelity")
root.iconText = "<"
d.resize();
usernameField.forceActiveFocus()
}
Connections {
target: loginDialog
onHandleLoginCompleted: {
console.log("Login Succeeded, linking steam account")
if (loginDialog.isSteamRunning()) {
loginDialog.linkSteam()
} else {
bodyLoader.setSource("WelcomeBody.qml", { "welcomeBack" : true })
bodyLoader.item.width = root.pane.width
bodyLoader.item.height = root.pane.height
}
}
onHandleLoginFailed: {
console.log("Login Failed")
}
onHandleLinkCompleted: {
console.log("Link Succeeded")
bodyLoader.setSource("WelcomeBody.qml", { "welcomeBack" : true })
bodyLoader.item.width = root.pane.width
bodyLoader.item.height = root.pane.height
}
onHandleLinkFailed: {
console.log("Link Failed")
}
}
Keys.onPressed: {
if (!visible) {
return
}
switch (event.key) {
case Qt.Key_Enter:
case Qt.Key_Return:
event.accepted = true
linkAccountBody.login()
break
}
}
}

View file

@ -19,8 +19,16 @@ import "../styles-uit"
Item {
id: recoverPasswordBody
clip: true
width: pane.width
height: pane.height
width: root.pane.width
height: root.pane.height
function send() {
loginDialog.sendRecoveryEmail(emailField.text)
bodyLoader.setSource("EmailSentBody.qml", { "email": emailField.text })
bodyLoader.item.width = root.pane.width
bodyLoader.item.height = root.pane.height
}
QtObject {
id: d
@ -70,6 +78,10 @@ Item {
width: 350
label: "Email address"
Component.onCompleted: {
emailField.forceActiveFocus()
}
}
Row {
@ -89,12 +101,20 @@ Item {
text: qsTr("Send recovery email")
color: hifi.buttons.blue
onClicked: recoverPasswordBody.send()
}
Button {
anchors.verticalCenter: parent.verticalCenter
text: qsTr("Back")
onClicked: {
bodyLoader.source = "LinkAccountBody.qml"
bodyLoader.item.width = root.pane.width
bodyLoader.item.height = root.pane.height
}
}
}
@ -103,4 +123,18 @@ Item {
root.iconText = "<"
d.resize();
}
Keys.onPressed: {
if (!visible) {
return
}
switch (event.key) {
case Qt.Key_Enter:
case Qt.Key_Return:
event.accepted = true
recoverPasswordBody.send()
break
}
}
}

View file

@ -107,4 +107,22 @@ Item {
root.iconText = ""
d.resize();
}
Connections {
target: loginDialog
onHandleLoginCompleted: {
console.log("Login Succeeded")
bodyLoader.setSource("WelcomeBody.qml", { "welcomeBack" : true })
bodyLoader.item.width = root.pane.width
bodyLoader.item.height = root.pane.height
}
onHandleLoginFailed: {
console.log("Login Failed")
bodyLoader.source = "CompleteProfileBody.qml"
bodyLoader.item.width = root.pane.width
bodyLoader.item.height = root.pane.height
}
}
}

View file

@ -19,8 +19,8 @@ import "../styles-uit"
Item {
id: usernameCollisionBody
clip: true
width: pane.width
height: pane.height
width: root.pane.width
height: root.pane.height
QtObject {
id: d
@ -30,26 +30,59 @@ Item {
readonly property int maxHeight: 720
function resize() {
var targetWidth = Math.max(titleWidth, mainTextContainer.visible ? mainTextContainer.contentWidth : 0)
var targetHeight = (mainTextContainer.visible ? mainTextContainer.height : 0) +
4 * hifi.dimensions.contentSpacing.y + form.height +
4 * hifi.dimensions.contentSpacing.y + buttons.height
var targetWidth = Math.max(titleWidth, Math.max(mainTextContainer.contentWidth,
termsContainer.contentWidth))
var targetHeight = mainTextContainer.height +
2 * hifi.dimensions.contentSpacing.y + textField.height +
5 * hifi.dimensions.contentSpacing.y + termsContainer.height +
1 * hifi.dimensions.contentSpacing.y + buttons.height
root.width = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth))
root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight))
}
}
MenuItem {
ShortcutText {
id: mainTextContainer
anchors {
top: parent.top
horizontalCenter: parent.horizontalCenter
left: parent.left
margins: 0
topMargin: hifi.dimensions.contentSpacing.y
}
text: qsTr("Choose your High Fidelity user name:")
text: qsTr("Your Steam username is not available.")
wrapMode: Text.WordWrap
color: hifi.colors.redAccent
lineHeight: 1
lineHeightMode: Text.ProportionalHeight
horizontalAlignment: Text.AlignHCenter
}
TextField {
id: textField
anchors {
top: mainTextContainer.bottom
left: parent.left
margins: 0
topMargin: 2 * hifi.dimensions.contentSpacing.y
}
width: 250
placeholderText: "Choose your own"
}
MenuItem {
id: termsContainer
anchors {
top: textField.bottom
left: parent.left
margins: 0
topMargin: 3 * hifi.dimensions.contentSpacing.y
}
text: qsTr("By creating this user profile, you agree to <a href=\"https://highfidelity.com/terms\">High Fidelity's Terms of Service</a>")
wrapMode: Text.WordWrap
color: hifi.colors.baseGrayHighlight
lineHeight: 1
@ -57,82 +90,13 @@ Item {
horizontalAlignment: Text.AlignHCenter
}
Column {
id: form
anchors {
top: mainTextContainer.bottom
left: parent.left
margins: 0
topMargin: 2 * hifi.dimensions.contentSpacing.y
}
spacing: 2 * hifi.dimensions.contentSpacing.y
Row {
spacing: hifi.dimensions.contentSpacing.x
TextField {
id: usernameField
anchors {
verticalCenter: parent.verticalCenter
}
width: 350
label: "User Name or Email"
}
ShortcutText {
anchors {
verticalCenter: parent.verticalCenter
}
text: "Need help?"
color: hifi.colors.blueAccent
font.underline: true
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
}
}
Row {
spacing: hifi.dimensions.contentSpacing.x
TextField {
id: passwordField
anchors {
verticalCenter: parent.verticalCenter
}
width: 350
label: "Password"
echoMode: TextInput.Password
}
ShortcutText {
anchors {
verticalCenter: parent.verticalCenter
}
text: "Need help?"
color: hifi.colors.blueAccent
font.underline: true
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
}
}
}
Row {
id: buttons
anchors {
top: form.bottom
top: termsContainer.bottom
right: parent.right
margins: 0
topMargin: 3 * hifi.dimensions.contentSpacing.y
topMargin: 1 * hifi.dimensions.contentSpacing.y
}
spacing: hifi.dimensions.contentSpacing.x
onHeightChanged: d.resize(); onWidthChanged: d.resize();
@ -143,6 +107,10 @@ Item {
text: qsTr("Create your profile")
color: hifi.buttons.blue
onClicked: {
loginDialog.createAccountFromStream(textField.text)
}
}
Button {
@ -159,4 +127,25 @@ Item {
root.iconText = "<"
d.resize();
}
Connections {
target: loginDialog
onHandleCreateCompleted: {
console.log("Create Succeeded")
loginDialog.loginThroughSteam()
}
onHandleCreateFailed: {
console.log("Create Failed: " + error)
}
onHandleLoginCompleted: {
console.log("Login Succeeded")
bodyLoader.setSource("WelcomeBody.qml", { "welcomeBack" : false })
bodyLoader.item.width = root.pane.width
bodyLoader.item.height = root.pane.height
}
onHandleLoginFailed: {
console.log("Login Failed")
}
}
}

View file

@ -20,7 +20,13 @@ Item {
width: pane.width
height: pane.height
property bool welcomeBack: true
property bool welcomeBack: false
function setTitle() {
root.title = (welcomeBack ? qsTr("Welcome back <b>") : qsTr("Welcome <b>")) + Account.username + qsTr("</b>!")
root.iconText = ""
d.resize();
}
QtObject {
id: d
@ -75,9 +81,10 @@ Item {
}
}
Component.onCompleted: {
root.title = (welcomeBack ? qsTr("Welcome back <b>") : qsTr("Welcome <b>")) + Account.getUsername() + qsTr("</b>!")
root.iconText = ""
d.resize();
Component.onCompleted: welcomeBody.setTitle()
Connections {
target: Account
onUsernameChanged: welcomeBody.setTitle()
}
}

View file

@ -15,6 +15,9 @@
AccountScriptingInterface* AccountScriptingInterface::getInstance() {
static AccountScriptingInterface sharedInstance;
auto accountManager = DependencyManager::get<AccountManager>();
QObject::connect(accountManager.data(), &AccountManager::profileChanged,
&sharedInstance, &AccountScriptingInterface::usernameChanged);
return &sharedInstance;
}

View file

@ -17,6 +17,11 @@
class AccountScriptingInterface : public QObject {
Q_OBJECT
Q_PROPERTY(QString username READ getUsername NOTIFY usernameChanged)
signals:
void usernameChanged();
public slots:
static AccountScriptingInterface* getInstance();
QString getUsername();

View file

@ -12,6 +12,8 @@
#include "LoginDialog.h"
#include <QDesktopServices>
#include <QJsonDocument>
#include <QNetworkReply>
#include <NetworkingConstants.h>
#include <steamworks-wrapper/SteamClient.h>
@ -52,6 +54,10 @@ void LoginDialog::toggleAction() {
}
}
bool LoginDialog::isSteamRunning() {
return SteamClient::isRunning();
}
void LoginDialog::login(const QString& username, const QString& password) {
qDebug() << "Attempting to login " << username;
DependencyManager::get<AccountManager>()->requestAccessToken(username, password);
@ -69,6 +75,92 @@ void LoginDialog::loginThroughSteam() {
});
}
void LoginDialog::linkSteam() {
qDebug() << "Attempting to link Steam account";
SteamClient::requestTicket([this](Ticket ticket) {
if (ticket.isNull()) {
emit handleLoginFailed();
return;
}
JSONCallbackParameters callbackParams;
callbackParams.jsonCallbackReceiver = this;
callbackParams.jsonCallbackMethod = "linkCompleted";
callbackParams.errorCallbackReceiver = this;
callbackParams.errorCallbackMethod = "linkFailed";
const QString LINK_STEAM_PATH = "api/v1/user/link_steam";
QJsonObject payload;
payload.insert("ticket", QJsonValue::fromVariant(QVariant(ticket)));
auto accountManager = DependencyManager::get<AccountManager>();
accountManager->sendRequest(LINK_STEAM_PATH, AccountManagerAuth::Required,
QNetworkAccessManager::PostOperation, callbackParams,
QJsonDocument(payload).toJson());
});
}
void LoginDialog::createAccountFromStream(QString username) {
qDebug() << "Attempting to create account from Steam info";
SteamClient::requestTicket([this, username](Ticket ticket) {
if (ticket.isNull()) {
emit handleLoginFailed();
return;
}
JSONCallbackParameters callbackParams;
callbackParams.jsonCallbackReceiver = this;
callbackParams.jsonCallbackMethod = "createCompleted";
callbackParams.errorCallbackReceiver = this;
callbackParams.errorCallbackMethod = "createFailed";
const QString CREATE_ACCOUNT_FROM_STEAM_PATH = "api/v1/user/create_from_steam";
QJsonObject payload;
payload.insert("ticket", QJsonValue::fromVariant(QVariant(ticket)));
if (!username.isEmpty()) {
payload.insert("username", QJsonValue::fromVariant(QVariant(username)));
}
auto accountManager = DependencyManager::get<AccountManager>();
accountManager->sendRequest(CREATE_ACCOUNT_FROM_STEAM_PATH, AccountManagerAuth::None,
QNetworkAccessManager::PostOperation, callbackParams,
QJsonDocument(payload).toJson());
});
}
void LoginDialog::openUrl(const QString& url) {
QDesktopServices::openUrl(url);
}
void LoginDialog::sendRecoveryEmail(const QString& email) {
const QString PASSWORD_RESET_PATH = "/users/password";
QJsonObject payload;
payload.insert("user_email", QJsonValue::fromVariant(QVariant(email)));
auto accountManager = DependencyManager::get<AccountManager>();
accountManager->sendRequest(PASSWORD_RESET_PATH, AccountManagerAuth::None,
QNetworkAccessManager::PostOperation, JSONCallbackParameters(),
QJsonDocument(payload).toJson());
}
void LoginDialog::linkCompleted(QNetworkReply& reply) {
emit handleLinkCompleted();
}
void LoginDialog::linkFailed(QNetworkReply& reply) {
emit handleLinkFailed(reply.errorString());
}
void LoginDialog::createCompleted(QNetworkReply& reply) {
emit handleCreateCompleted();
}
void LoginDialog::createFailed(QNetworkReply& reply) {
emit handleCreateFailed(reply.errorString());
}

View file

@ -16,6 +16,8 @@
#include <OffscreenQmlDialog.h>
class QNetworkReply;
class LoginDialog : public OffscreenQmlDialog {
Q_OBJECT
HIFI_QML_DECL
@ -29,10 +31,30 @@ signals:
void handleLoginCompleted();
void handleLoginFailed();
protected:
void handleLinkCompleted();
void handleLinkFailed(QString error);
void handleCreateCompleted();
void handleCreateFailed(QString error);
public slots:
void linkCompleted(QNetworkReply& reply);
void linkFailed(QNetworkReply& reply);
void createCompleted(QNetworkReply& reply);
void createFailed(QNetworkReply& reply);
protected slots:
Q_INVOKABLE bool isSteamRunning();
Q_INVOKABLE void login(const QString& username, const QString& password);
Q_INVOKABLE void loginThroughSteam();
Q_INVOKABLE void linkSteam();
Q_INVOKABLE void createAccountFromStream(QString username = QString());
Q_INVOKABLE void openUrl(const QString& url);
Q_INVOKABLE void sendRecoveryEmail(const QString& email);
};
#endif // hifi_LoginDialog_h

View file

@ -568,6 +568,7 @@ void AccountManager::requestAccessTokenFinished() {
void AccountManager::requestAccessTokenError(QNetworkReply::NetworkError error) {
// TODO: error handling
qCDebug(networking) << "AccountManager requestError - " << error;
emit loginFailed();
}
void AccountManager::requestProfile() {

View file

@ -133,8 +133,16 @@ void SteamTicketRequests::onGetAuthSessionTicketResponse(GetAuthSessionTicketRes
static std::atomic_bool initialized { false };
static std::unique_ptr<SteamTicketRequests> steamTicketRequests;
bool SteamClient::init() {
bool SteamClient::isRunning() {
if (!initialized) {
init();
}
return initialized;
}
bool SteamClient::init() {
if (SteamAPI_IsSteamRunning() && !initialized) {
initialized = SteamAPI_Init();
}
@ -157,11 +165,6 @@ void SteamClient::shutdown() {
void SteamClient::runCallbacks() {
if (!initialized) {
init();
}
if (!initialized) {
qDebug() << "Steam not initialized";
return;
}
@ -176,7 +179,13 @@ void SteamClient::runCallbacks() {
void SteamClient::requestTicket(TicketRequestCallback callback) {
if (!initialized) {
init();
if (SteamAPI_IsSteamRunning()) {
init();
} else {
qWarning() << "Steam is not running";
callback(INVALID_TICKET);
return;
}
}
if (!initialized) {

View file

@ -22,6 +22,8 @@ using TicketRequestCallback = std::function<void(Ticket)>;
class SteamClient {
public:
static bool isRunning();
static bool init();
static void shutdown();