Merge pull request #14727 from wayne-chen/oculusLoginFeature

MS20311: Oculus login feature
This commit is contained in:
Jeff Clinton 2019-01-25 16:16:32 -08:00 committed by GitHub
commit f78fdffeda
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
30 changed files with 991 additions and 223 deletions

View file

@ -120,6 +120,6 @@ FocusScope {
}
Component.onCompleted: {
bodyLoader.setSource("LoginDialog/LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": false });
bodyLoader.setSource("LoginDialog/LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": false, "linkOculus": false });
}
}

View file

@ -22,11 +22,16 @@ Item {
width: root.width
height: root.height
readonly property string termsContainerText: qsTr("By creating this user profile, you agree to High Fidelity's Terms of Service")
readonly property string termsContainerOculusText: qsTr("By signing up, you agree to High Fidelity's Terms of Service")
readonly property int textFieldHeight: 31
readonly property string fontFamily: "Raleway"
readonly property int fontSize: 15
readonly property bool fontBold: true
readonly property int textFieldFontSize: 18
readonly property var passwordImageRatio: 16 / 23
readonly property bool withSteam: withSteam
property bool withOculus: withOculus
property bool withSteam: withSteam
property string errorString: errorString
readonly property bool loginDialogPoppedUp: loginDialog.getLoginDialogPoppedUp()
@ -61,15 +66,20 @@ Item {
Item {
id: contentItem
anchors.fill: parent
width: parent.width
height: errorContainer.height + fields.height + buttons.height + additionalTextContainer.height +
termsContainer.height
anchors.top: parent.top
anchors.topMargin: root.bannerHeight + 0.25 * parent.height
anchors.left: parent.left
Item {
id: errorContainer
width: parent.width
width: root.bannerWidth
height: loginErrorMessageTextMetrics.height
anchors {
bottom: buttons.top;
bottomMargin: hifi.dimensions.contentSpacing.y;
bottom: completeProfileBody.withOculus ? fields.top : buttons.top;
bottomMargin: 1.5 * hifi.dimensions.contentSpacing.y;
left: buttons.left;
}
TextMetrics {
@ -79,8 +89,8 @@ Item {
}
Text {
id: loginErrorMessage;
width: root.bannerWidth
color: "red";
width: root.bannerWidth;
font.family: completeProfileBody.fontFamily
font.pixelSize: 18
font.bold: completeProfileBody.fontBold
@ -88,13 +98,196 @@ Item {
horizontalAlignment: Text.AlignHCenter
text: completeProfileBody.errorString
visible: true
onTextChanged: {
mainContainer.recalculateErrorMessage();
}
Component.onCompleted: {
mainContainer.recalculateErrorMessage();
}
}
Component.onCompleted: {
if (loginErrorMessageTextMetrics.width > root.bannerWidth && root.isTablet) {
loginErrorMessage.wrapMode = Text.WordWrap;
loginErrorMessage.verticalAlignment = Text.AlignLeft;
loginErrorMessage.horizontalAlignment = Text.AlignLeft;
errorContainer.height = 3 * loginErrorMessageTextMetrics.height;
}
Item {
id: fields
width: root.bannerWidth
height: 3 * completeProfileBody.textFieldHeight + 2 * hifi.dimensions.contentSpacing.y
visible: completeProfileBody.withOculus
anchors {
left: parent.left
leftMargin: (parent.width - root.bannerWidth) / 2
bottom: buttons.top
bottomMargin: hifi.dimensions.contentSpacing.y
}
HifiControlsUit.TextField {
id: usernameField
width: root.bannerWidth
height: completeProfileBody.textFieldHeight
placeholderText: "Username"
font.pixelSize: completeProfileBody.textFieldFontSize
styleRenderType: Text.QtRendering
anchors {
top: parent.top
}
Keys.onPressed: {
if (!usernameField.visible) {
return;
}
switch (event.key) {
case Qt.Key_Tab:
event.accepted = true;
if (event.modifiers === Qt.ShiftModifier) {
passwordField.focus = true;
} else {
emailField.focus = true;
}
break;
case Qt.Key_Backtab:
event.accepted = true;
passwordField.focus = true;
break;
case Qt.Key_Enter:
case Qt.Key_Return:
event.accepted = true;
loginDialog.createAccountFromOculus(emailField.text, usernameField.text, passwordField.text);
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": completeProfileBody.withSteam,
"linkSteam": false, "withOculus": completeProfileBody.withOculus, "linkOculus": false, "createOculus": true });
break;
}
}
onFocusChanged: {
root.text = "";
if (focus) {
root.isPassword = false;
}
}
Component.onCompleted: {
var userID = "";
if (completeProfileBody.withOculus) {
userID = loginDialog.oculusUserID();
}
usernameField.text = userID;
}
}
HifiControlsUit.TextField {
id: emailField
width: root.bannerWidth
height: completeProfileBody.textFieldHeight
anchors {
top: usernameField.bottom
topMargin: hifi.dimensions.contentSpacing.y
}
placeholderText: "Email"
font.pixelSize: completeProfileBody.textFieldFontSize
styleRenderType: Text.QtRendering
activeFocusOnPress: true
Keys.onPressed: {
switch (event.key) {
case Qt.Key_Tab:
event.accepted = true;
if (event.modifiers === Qt.ShiftModifier) {
usernameField.focus = true;
} else {
passwordField.focus = true;
}
break;
case Qt.Key_Backtab:
event.accepted = true;
usernameField.focus = true;
break;
case Qt.Key_Enter:
case Qt.Key_Return:
event.accepted = true;
loginDialog.createAccountFromOculus(emailField.text, usernameField.text, passwordField.text);
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": completeProfileBody.withSteam,
"linkSteam": false, "withOculus": completeProfileBody.withOculus, "linkOculus": false, "createOculus": true });
break;
}
}
onFocusChanged: {
root.text = "";
if (focus) {
root.isPassword = false;
}
}
}
HifiControlsUit.TextField {
id: passwordField
width: root.bannerWidth
height: completeProfileBody.textFieldHeight
placeholderText: "Password (optional)"
font.pixelSize: completeProfileBody.textFieldFontSize
styleRenderType: Text.QtRendering
activeFocusOnPress: true
echoMode: passwordFieldMouseArea.showPassword ? TextInput.Normal : TextInput.Password
anchors {
top: emailField.bottom
topMargin: hifi.dimensions.contentSpacing.y
}
onFocusChanged: {
root.text = "";
root.isPassword = focus;
}
Item {
id: showPasswordContainer
z: 10
// width + image's rightMargin
width: showPasswordImage.width + 8
height: parent.height
anchors {
right: parent.right
}
Image {
id: showPasswordImage
width: passwordField.height * passwordImageRatio
height: passwordField.height * passwordImageRatio
anchors {
right: parent.right
rightMargin: 8
top: parent.top
topMargin: passwordFieldMouseArea.showPassword ? 6 : 8
bottom: parent.bottom
bottomMargin: passwordFieldMouseArea.showPassword ? 5 : 8
}
source: passwordFieldMouseArea.showPassword ? "../../images/eyeClosed.svg" : "../../images/eyeOpen.svg"
MouseArea {
id: passwordFieldMouseArea
anchors.fill: parent
acceptedButtons: Qt.LeftButton
property bool showPassword: false
onClicked: {
showPassword = !showPassword;
}
}
}
}
Keys.onPressed: {
switch (event.key) {
case Qt.Key_Tab:
event.accepted = true;
if (event.modifiers === Qt.ShiftModifier) {
emailField.focus = true;
} else if (usernameField.visible) {
usernameField.focus = true;
} else {
emailField.focus = true;
}
break;
case Qt.Key_Backtab:
event.accepted = true;
emailField.focus = true;
break;
case Qt.Key_Enter:
case Qt.Key_Return:
event.accepted = true;
loginDialog.createAccountFromOculus(emailField.text, usernameField.text, passwordField.text);
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": completeProfileBody.withSteam,
"linkSteam": false, "withOculus": completeProfileBody.withOculus, "linkOculus": false, "createOculus": true });
break;
}
}
}
}
@ -105,7 +298,7 @@ Item {
height: d.minHeightButton
anchors {
top: parent.top
topMargin: (parent.height - additionalTextContainer.height) / 2 - hifi.dimensions.contentSpacing.y
topMargin: (parent.height - additionalTextContainer.height + fields.height) / 2 - hifi.dimensions.contentSpacing.y
left: parent.left
leftMargin: (parent.width - root.bannerWidth) / 2
}
@ -144,7 +337,7 @@ Item {
width: (parent.width - hifi.dimensions.contentSpacing.x) / 2
height: d.minHeightButton
text: qsTr("Create your profile")
text: completeProfileBody.withOculus ? qsTr("Sign Up") : qsTr("Create your profile")
color: hifi.buttons.blue
fontFamily: completeProfileBody.fontFamily
@ -158,55 +351,12 @@ Item {
UserActivityLogger.logAction("encourageLoginDialog", data);
}
loginErrorMessage.visible = false;
loginDialog.createAccountFromSteam();
}
}
}
Item {
id: additionalTextContainer
width: parent.width
height: additionalTextMetrics.height
anchors {
top: buttons.bottom
horizontalCenter: parent.horizontalCenter
topMargin: hifi.dimensions.contentSpacing.y
left: parent.left
}
TextMetrics {
id: additionalTextMetrics
font: additionalText.font
text: "Already have a High Fidelity profile? Link to an existing profile here."
}
HifiStylesUit.ShortcutText {
id: additionalText
text: "<a href='https://fake.link'>Already have a High Fidelity profile? Link to an existing profile here.</a>"
font.family: completeProfileBody.fontFamily
font.pixelSize: completeProfileBody.fontSize
font.bold: completeProfileBody.fontBold
wrapMode: Text.NoWrap
lineHeight: 1
lineHeightMode: Text.ProportionalHeight
horizontalAlignment: Text.AlignHCenter
linkColor: hifi.colors.blueAccent
onLinkActivated: {
loginDialog.isLogIn = true;
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "errorString": "", "withSteam": true, "linkSteam": true });
}
Component.onCompleted: {
if (additionalTextMetrics.width > root.bannerWidth && root.isTablet) {
additionalText.width = root.bannerWidth;
additionalText.wrapMode = Text.WordWrap;
additionalText.verticalAlignment = Text.AlignLeft;
additionalText.horizontalAlignment = Text.AlignLeft;
additionalTextContainer.height = (additionalTextMetrics.width / root.bannerWidth) * additionalTextMetrics.height;
additionalTextContainer.anchors.left = buttons.left;
} else {
additionalText.anchors.centerIn = additionalTextContainer;
if (completeProfileBody.withOculus) {
loginDialog.createAccountFromOculus(emailField.text, usernameField.text, passwordField.text);
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": completeProfileBody.withSteam,
"linkSteam": false, "withOculus": completeProfileBody.withOculus, "linkOculus": false, "createOculus": true });
} else if (completeProfileBody.withSteam) {
loginDialog.createAccountFromSteam();
}
}
}
@ -217,29 +367,33 @@ Item {
width: parent.width
height: termsTextMetrics.height
anchors {
top: additionalTextContainer.bottom
top: buttons.bottom
horizontalCenter: parent.horizontalCenter
topMargin: 2 * hifi.dimensions.contentSpacing.y
topMargin: hifi.dimensions.contentSpacing.y
left: parent.left
}
TextMetrics {
id: termsTextMetrics
font: termsText.font
text: completeProfileBody.termsContainerText
text: completeProfileBody.withOculus ? completeProfileBody.termsContainerOculusText : completeProfileBody.termsContainerText
Component.onCompleted: {
// with the link.
termsText.text = qsTr("By creating this user profile, you agree to <a href='https://highfidelity.com/terms'>High Fidelity's Terms of Service</a>")
if (completeProfileBody.withOculus) {
termsText.text = qsTr("By signing up, you agree to <a href='https://highfidelity.com/terms'>High Fidelity's Terms of Service</a>")
} else {
termsText.text = qsTr("By creating this user profile, you agree to <a href='https://highfidelity.com/terms'>High Fidelity's Terms of Service</a>")
}
}
}
HifiStylesUit.InfoItem {
id: termsText
text: completeProfileBody.termsContainerText
text: completeProfileBody.withOculus ? completeProfileBody.termsContainerOculusText : completeProfileBody.termsContainerText
font.family: completeProfileBody.fontFamily
font.pixelSize: completeProfileBody.fontSize
font.bold: completeProfileBody.fontBold
wrapMode: Text.WordWrap
color: hifi.colors.lightGray
color: hifi.colors.white
linkColor: hifi.colors.blueAccent
lineHeight: 1
lineHeightMode: Text.ProportionalHeight
@ -247,7 +401,7 @@ Item {
onLinkActivated: loginDialog.openUrl(link);
Component.onCompleted: {
if (termsTextMetrics.width > root.bannerWidth && root.isTablet) {
if (termsTextMetrics.width > root.bannerWidth) {
termsText.width = root.bannerWidth;
termsText.wrapMode = Text.WordWrap;
additionalText.verticalAlignment = Text.AlignLeft;
@ -260,14 +414,86 @@ Item {
}
}
}
Item {
id: additionalTextContainer
width: parent.width
height: additionalTextMetrics.height
anchors {
top: termsContainer.bottom
horizontalCenter: parent.horizontalCenter
topMargin: 2 * hifi.dimensions.contentSpacing.y
left: parent.left
}
TextMetrics {
id: additionalTextMetrics
font: additionalText.font
text: "Already have a High Fidelity profile? Link to an existing profile here."
}
HifiStylesUit.ShortcutText {
id: additionalText
text: "<a href='https://fake.link'>Already have a High Fidelity profile? Link to an existing profile here.</a>"
width: root.bannerWidth;
font.family: completeProfileBody.fontFamily
font.pixelSize: completeProfileBody.fontSize
font.bold: completeProfileBody.fontBold
wrapMode: Text.NoWrap
lineHeight: 1
lineHeightMode: Text.ProportionalHeight
horizontalAlignment: Text.AlignHCenter
linkColor: hifi.colors.blueAccent
onLinkActivated: {
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "errorString": "",
"withSteam": completeProfileBody.withSteam, "linkSteam": completeProfileBody.withSteam, "withOculus": completeProfileBody.withOculus,
"linkOculus": completeProfileBody.withOculus });
}
Component.onCompleted: {
if (additionalTextMetrics.width > root.bannerWidth) {
additionalText.wrapMode = Text.WordWrap;
additionalText.verticalAlignment = Text.AlignLeft;
additionalText.horizontalAlignment = Text.AlignLeft;
additionalTextContainer.height = (additionalTextMetrics.width / root.bannerWidth) * additionalTextMetrics.height;
additionalTextContainer.anchors.left = buttons.left;
} else {
additionalText.anchors.centerIn = additionalTextContainer;
}
}
}
}
}
function recalculateErrorMessage() {
if (completeProfileBody.errorString !== "") {
loginErrorMessage.visible = true;
var errorLength = completeProfileBody.errorString.split(/\r\n|\r|\n/).length;
var errorStringEdited = completeProfileBody.errorString.replace(/[\n\r]+/g, "\n");
loginErrorMessage.text = errorStringEdited;
if (errorLength > 1.0) {
loginErrorMessage.wrapMode = Text.WordWrap;
loginErrorMessage.verticalAlignment = Text.AlignLeft;
loginErrorMessage.horizontalAlignment = Text.AlignLeft;
errorContainer.height = errorLength * loginErrorMessageTextMetrics.height;
} else if (loginErrorMessageTextMetrics.width > root.bannerWidth) {
loginErrorMessage.wrapMode = Text.WordWrap;
loginErrorMessage.verticalAlignment = Text.AlignLeft;
loginErrorMessage.horizontalAlignment = Text.AlignLeft;
errorContainer.height = (loginErrorMessageTextMetrics.width / root.bannerWidth) * loginErrorMessageTextMetrics.height;
} else {
loginErrorMessage.wrapMode = Text.NoWrap;
loginErrorMessage.verticalAlignment = Text.AlignVCenter;
loginErrorMessage.horizontalAlignment = Text.AlignHCenter;
errorContainer.height = loginErrorMessageTextMetrics.height;
}
}
}
}
Connections {
target: loginDialog
onHandleCreateCompleted: {
console.log("Create Succeeded")
console.log("Create Succeeded");
if (completeProfileBody.withSteam) {
if (completeProfileBody.loginDialogPoppedUp) {
var data = {
@ -277,20 +503,24 @@ Item {
}
loginDialog.loginThroughSteam();
}
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": completeProfileBody.withSteam, "linkSteam": false });
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": completeProfileBody.withSteam, "linkSteam": false,
"withOculus": completeProfileBody.withOculus, "linkOculus": false });
}
onHandleCreateFailed: {
console.log("Create Failed: " + error);
if (completeProfileBody.withSteam) {
if (completeProfileBody.withSteam || completeProfileBody.withOculus) {
if (completeProfileBody.loginDialogPoppedUp) {
action = completeProfileBody.withSteam ? "Steam" : "Oculus";
var data = {
"action": "user failed to create a profile with Steam from the complete profile screen"
"action": "user failed to create a profile with " + action + " from the complete profile screen"
}
UserActivityLogger.logAction("encourageLoginDialog", data);
}
}
bodyLoader.setSource("UsernameCollisionBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": completeProfileBody.withSteam });
if (!completeProfileBody.withOculus) {
bodyLoader.setSource("UsernameCollisionBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": completeProfileBody.withSteam,
"withOculus": completeProfileBody.withOculus });
}
}
}
@ -302,5 +532,6 @@ Item {
}
d.resize();
root.text = "";
usernameField.forceActiveFocus();
}
}

View file

@ -36,9 +36,10 @@ Item {
property bool keyboardRaised: false
property bool punctuationMode: false
property bool withSteam: false
property bool withSteam: withSteam
property bool linkSteam: linkSteam
property bool withOculus: false
property bool withOculus: withOculus
property bool linkOculus: linkOculus
property string errorString: errorString
property bool lostFocus: false
@ -83,23 +84,24 @@ Item {
}
UserActivityLogger.logAction("encourageLoginDialog", data);
}
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": linkAccountBody.withSteam, "withOculus": linkAccountBody.withOculus, "linkSteam": linkAccountBody.linkSteam });
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": linkAccountBody.withSteam,
"withOculus": linkAccountBody.withOculus, "linkSteam": linkAccountBody.linkSteam, "linkOculus": linkAccountBody.linkOculus });
}
function init() {
// going to/from sign in/up dialog.
loginDialog.isLogIn = true;
loginErrorMessage.text = linkAccountBody.errorString;
loginErrorMessage.visible = (linkAccountBody.errorString !== "");
loginButton.text = !linkAccountBody.linkSteam ? "Log In" : "Link Account";
if (loginErrorMessageTextMetrics.width > emailField.width) {
loginErrorMessage.wrapMode = Text.WordWrap;
errorContainer.height = (loginErrorMessageTextMetrics.width / emailField.width) * loginErrorMessageTextMetrics.height;
}
loginButton.text = (!linkAccountBody.linkSteam && !linkAccountBody.linkOculus) ? "Log In" : "Link Account";
loginButton.color = hifi.buttons.blue;
emailField.placeholderText = "Username or Email";
var savedUsername = Settings.getValue("keepMeLoggedIn/savedUsername", "");
emailField.text = keepMeLoggedInCheckbox.checked ? savedUsername === "Unknown user" ? "" : savedUsername : "";
if (linkAccountBody.linkSteam) {
steamInfoText.anchors.top = passwordField.bottom;
keepMeLoggedInCheckbox.anchors.top = steamInfoText.bottom;
if (linkAccountBody.linkSteam || linkAccountBody.linkOculus) {
loginButton.width = (passwordField.width - hifi.dimensions.contentSpacing.x) / 2;
loginButton.anchors.right = emailField.right;
} else {
@ -125,7 +127,7 @@ Item {
id: loginContainer
width: emailField.width
height: errorContainer.height + emailField.height + passwordField.height + 5.5 * hifi.dimensions.contentSpacing.y +
keepMeLoggedInCheckbox.height + loginButton.height + cantAccessTextMetrics.height + continueButton.height + steamInfoTextMetrics.height
keepMeLoggedInCheckbox.height + loginButton.height + cantAccessTextMetrics.height + continueButton.height
anchors {
top: parent.top
topMargin: root.bannerHeight + 0.25 * parent.height
@ -135,7 +137,7 @@ Item {
Item {
id: errorContainer
width: loginErrorMessageTextMetrics.width
width: parent.width
height: loginErrorMessageTextMetrics.height
anchors {
bottom: emailField.top;
@ -304,7 +306,7 @@ Item {
fontSize: linkAccountBody.fontSize
fontBold: linkAccountBody.fontBold
color: hifi.buttons.noneBorderlessWhite;
visible: linkAccountBody.linkSteam
visible: linkAccountBody.linkSteam || linkAccountBody.linkOculus
anchors {
top: keepMeLoggedInCheckbox.bottom
topMargin: hifi.dimensions.contentSpacing.y
@ -315,10 +317,9 @@ Item {
"action": "user clicked cancel at link account screen"
};
UserActivityLogger.logAction("encourageLoginDialog", data);
loginDialog.dismissLoginDialog();
}
bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": linkAccountBody.withSteam, "errorString": "" });
bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": linkAccountBody.withSteam,
"withOculus": linkAccountBody.withOculus, "errorString": "" });
}
}
HifiControlsUit.Button {
@ -337,33 +338,6 @@ Item {
linkAccountBody.login();
}
}
TextMetrics {
id: steamInfoTextMetrics
font: steamInfoText.font
text: steamInfoText.text
}
Text {
id: steamInfoText
width: root.bannerWidth
visible: linkAccountBody.linkSteam
anchors {
top: loginButton.bottom
topMargin: hifi.dimensions.contentSpacing.y
left: emailField.left
}
font.family: linkAccountBody.fontFamily
font.pixelSize: linkAccountBody.textFieldFontSize
color: "white"
text: qsTr("Your Steam account information will not be exposed to others.");
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
Component.onCompleted: {
if (steamInfoTextMetrics.width > root.bannerWidth) {
steamInfoText.wrapMode = Text.WordWrap;
}
}
}
TextMetrics {
id: cantAccessTextMetrics
font: cantAccessText.font
@ -372,7 +346,7 @@ Item {
HifiStylesUit.ShortcutText {
id: cantAccessText
z: 10
visible: !linkAccountBody.linkSteam
visible: !linkAccountBody.linkSteam && !linkAccountBody.linkOculus
anchors {
top: loginButton.bottom
topMargin: hifi.dimensions.contentSpacing.y
@ -423,10 +397,10 @@ Item {
buttonGlyphSize: 24
buttonGlyphRightMargin: 10
onClicked: {
// if (loginDialog.isOculusStoreRunning()) {
// linkAccountBody.withOculus = true;
// loginDialog.loginThroughSteam();
// } else
if (loginDialog.isOculusRunning()) {
linkAccountBody.withOculus = true;
loginDialog.loginThroughOculus();
} else
if (loginDialog.isSteamRunning()) {
linkAccountBody.withSteam = true;
loginDialog.loginThroughSteam();
@ -446,18 +420,17 @@ Item {
}
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader,
"withSteam": linkAccountBody.withSteam, "withOculus": linkAccountBody.withOculus, "linkSteam": linkAccountBody.linkSteam });
"withSteam": linkAccountBody.withSteam, "withOculus": linkAccountBody.withOculus, "linkSteam": linkAccountBody.linkSteam, "linkOculus": linkAccountBody.linkOculus });
}
Component.onCompleted: {
if (linkAccountBody.linkSteam) {
if (linkAccountBody.linkSteam || linkAccountBody.linkOculus) {
continueButton.visible = false;
return;
}
// if (loginDialog.isOculusStoreRunning()) {
// continueButton.text = qsTr("CONTINUE WITH OCULUS");
// continueButton.buttonGlyph = hifi.glyphs.oculus;
// } else
if (loginDialog.isSteamRunning()) {
if (loginDialog.isOculusRunning()) {
continueButton.text = qsTr("CONTINUE WITH OCULUS");
continueButton.buttonGlyph = hifi.glyphs.oculus;
} else if (loginDialog.isSteamRunning()) {
continueButton.text = qsTr("CONTINUE WITH STEAM");
continueButton.buttonGlyph = hifi.glyphs.steamSquare;
} else {
@ -470,7 +443,7 @@ Item {
id: signUpContainer
width: loginContainer.width
height: signUpTextMetrics.height
visible: !linkAccountBody.linkSteam
visible: !linkAccountBody.linkSteam && !linkAccountBody.linkOculus
anchors {
left: loginContainer.left
top: loginContainer.bottom
@ -519,7 +492,7 @@ Item {
UserActivityLogger.logAction("encourageLoginDialog", data);
}
bodyLoader.setSource("SignUpBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader,
"errorString": "", "linkSteam": linkAccountBody.linkSteam });
"errorString": "" });
}
}
}
@ -543,7 +516,7 @@ Item {
fontFamily: linkAccountBody.fontFamily
fontSize: linkAccountBody.fontSize
fontBold: linkAccountBody.fontBold
visible: linkAccountBody.loginDialogPoppedUp && !linkAccountBody.linkSteam;
visible: loginDialog.getLoginDialogPoppedUp() && !linkAccountBody.linkSteam && !linkAccountBody.linkOculus;
onClicked: {
if (linkAccountBody.loginDialogPoppedUp) {
var data = {

View file

@ -29,6 +29,8 @@ Item {
property bool withSteam: withSteam
property bool withOculus: withOculus
property bool linkSteam: linkSteam
property bool linkOculus: linkOculus
property bool createOculus: createOculus
readonly property bool loginDialogPoppedUp: loginDialog.getLoginDialogPoppedUp()
@ -75,15 +77,25 @@ Item {
}
}
Timer {
id: oculusSuccessTimer
interval: 500;
running: false;
repeat: false;
onTriggered: {
loginDialog.loginThroughOculus();
init();
}
}
function init() {
// For the process of logging in.
loggingInText.wrapMode = Text.NoWrap;
if (loggingInBody.linkSteam) {
if (loggingInBody.createOculus) {
loggingInGlyph.text = hifi.glyphs.oculus;
loggingInGlyph.visible = true;
loggingInText.text = "Linking to Steam";
loggingInText.text = "Creating account with Oculus";
loggingInText.x = loggingInHeader.width/2 - loggingInTextMetrics.width/2 + loggingInGlyphTextMetrics.width/2;
loginDialog.linkSteam();
} else if (loggingInBody.withSteam) {
loggingInGlyph.visible = true;
loggingInText.text = "Logging in to Steam";
@ -100,12 +112,18 @@ Item {
loggingInSpinner.visible = true;
}
function loadingSuccess() {
loggingInSpinner.visible = false;
if (loggingInBody.linkSteam) {
loggingInText.text = "Linking to Steam";
loggingInText.x = loggingInHeader.width/2 - loggingInTextMetrics.width/2 + loggingInGlyphTextMetrics.width/2;
loginDialog.linkSteam();
return;
} else if (loggingInBody.linkOculus) {
loggingInText.text = "Linking to Oculus";
loggingInText.x = loggingInHeader.width/2 - loggingInTextMetrics.width/2 + loggingInGlyphTextMetrics.width/2;
loginDialog.linkOculus();
return;
}
loggingInSpinner.visible = false;
if (loggingInBody.withSteam) {
// reset the flag.
loggingInGlyph.visible = false;
@ -246,6 +264,26 @@ Item {
verticalAlignment: Text.AlignVCenter;
visible: false;
}
HifiControlsUit.Button {
id: okButton;
width: d.minWidthButton
height: d.minHeightButton
text: qsTr("OK")
color: hifi.buttons.white
anchors {
top: loggedInGlyph.bottom
topMargin: 3 * hifi.dimensions.contentSpacing.y
left: parent.left
leftMargin: (parent.width - width) / 2;
}
onClicked: {
root.tryDestroy();
if (loginDialog.getLoginDialogPoppedUp()) {
loginDialog.dismissLoginDialog();
}
}
visible: false
}
}
}
}
@ -257,6 +295,34 @@ Item {
Connections {
target: loginDialog
onHandleCreateCompleted: {
console.log("Create Succeeded")
if (loggingInBody.withOculus) {
if (loggingInBody.loginDialogPoppedUp) {
var data = {
"action": "user created Oculus account successfully"
};
UserActivityLogger.logAction("encourageLoginDialog", data);
}
loggingInBody.createOculus = false;
loggingInText.text = "Account created!";
loggingInText.x = loggingInHeader.width/2 - loggingInTextMetrics.width/2 + loggingInGlyphTextMetrics.width/2;
oculusSuccessTimer.start();
}
}
onHandleCreateFailed: {
console.log("Create Failed: " + error);
if (loggingInBody.withOculus) {
if (loggingInBody.loginDialogPoppedUp) {
var data = {
"action": "user created Oculus account unsuccessfully"
};
UserActivityLogger.logAction("encourageLoginDialog", data);
}
bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": loggingInBody.withSteam,
"withOculus": loggingInBody.withOculus, "errorString": error });
}
}
onHandleLinkCompleted: {
console.log("Link Succeeded");
if (loggingInBody.linkSteam) {
@ -267,21 +333,40 @@ Item {
};
UserActivityLogger.logAction("encourageLoginDialog", data);
}
loggingInBody.loadingSuccess();
} else if (loggingInBody.linkOculus) {
loggingInBody.linkOculus = false;
if (loggingInBody.loginDialogPoppedUp) {
var data = {
"action": "user linked Oculus with their hifi account credentials successfully"
};
UserActivityLogger.logAction("encourageLoginDialog", data);
}
}
loggingInBody.loadingSuccess();
}
onHandleLinkFailed: {
console.log("Link Failed: " + error);
if (loggingInBody.linkSteam) {
loggingInSpinner.visible = false;
if (loggingInBody.linkOculus) {
loggingInText.text = "Oculus failed to link";
if (loggingInBody.loginDialogPoppedUp) {
var data = {
"action": "user linked Oculus unsuccessfully"
};
UserActivityLogger.logAction("encourageLoginDialog", data);
}
okButton.visible = true;
} else if (loggingInBody.linkSteam){
if (loggingInBody.loginDialogPoppedUp) {
var data = {
"action": "user linked Steam unsuccessfully"
};
UserActivityLogger.logAction("encourageLoginDialog", data);
}
} else {
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": loggingInBody.linkSteam,
"linkOculus": loggingInBody.linkOculus, "errorString": error });
}
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": true, "errorString": error });
}
onHandleLoginCompleted: {
@ -292,8 +377,19 @@ Item {
onHandleLoginFailed: {
console.log("Login Failed")
loggingInSpinner.visible = false;
loggingInGlyph.visible = false;
var errorString = "";
if (loggingInBody.linkSteam && loggingInBody.withSteam) {
if (loggingInBody.linkOculus && loggingInBody.withOculus) {
errorString = "Username or password is incorrect.";
if (loggingInBody.loginDialogPoppedUp) {
var data = {
"action": "user failed to link Oculus with their hifi account credentials"
};
UserActivityLogger.logAction("encourageLoginDialog", data);
}
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": loggingInBody.withSteam,
"withOculus": loggingInBody.withOculus, "linkSteam": loggingInBody.linkSteam, "linkOculus": loggingInBody.linkOculus, "errorString": errorString });
} else if (loggingInBody.linkSteam && loggingInBody.withSteam) {
errorString = "Username or password is incorrect.";
if (loggingInBody.loginDialogPoppedUp) {
var data = {
@ -301,9 +397,9 @@ Item {
};
UserActivityLogger.logAction("encourageLoginDialog", data);
}
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": loggingInBody.withSteam, "linkSteam": loggingInBody.linkSteam, "errorString": errorString });
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": loggingInBody.withSteam,
"withOculus": loggingInBody.withOculus, "linkSteam": loggingInBody.linkSteam, "linkOculus": loggingInBody.linkOculus, "errorString": errorString });
} else if (loggingInBody.withSteam) {
loggingInGlyph.visible = false;
errorString = "Your Steam authentication has failed. Please make sure you are logged into Steam and try again.";
if (loggingInBody.loginDialogPoppedUp) {
var data = {
@ -311,19 +407,19 @@ Item {
};
UserActivityLogger.logAction("encourageLoginDialog", data);
}
bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": loggingInBody.withSteam, "errorString": errorString });
bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": loggingInBody.withSteam,
"withOculus": loggingInBody.withOculus, "linkSteam": loggingInBody.linkSteam, "linkOculus": loggingInBody.linkOculus, "errorString": errorString });
} else if (loggingInBody.withOculus) {
loggingInGlyph.visible = false;
errorString = "Your Oculus authentication has failed. Please make sure you are logged into Oculus and try again."
errorString = "Your Oculus account is not connected to an existing High Fidelity account. Please create a new one."
if (loggingInBody.loginDialogPoppedUp) {
var data = {
"action": "user failed to authenticate with Oculus to log in"
};
UserActivityLogger.logAction("encourageLoginDialog", data);
}
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "errorString": errorString });
}
else {
bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": loggingInBody.withSteam,
"withOculus": loggingInBody.withOculus, "linkSteam": loggingInBody.linkSteam, "linkOculus": loggingInBody.linkOculus, "errorString": errorString });
} else {
errorString = "Username or password is incorrect.";
if (loggingInBody.loginDialogPoppedUp) {
var data = {

View file

@ -23,6 +23,7 @@ Item {
clip: true
height: root.height
width: root.width
readonly property string termsContainerText: qsTr("By signing up, you agree to High Fidelity's Terms of Service")
property int textFieldHeight: 31
property string fontFamily: "Raleway"
property int fontSize: 15
@ -37,7 +38,6 @@ Item {
onKeyboardRaisedChanged: d.resize();
property string errorString: errorString
property bool linkSteam: linkSteam
property bool lostFocus: false
readonly property bool loginDialogPoppedUp: loginDialog.getLoginDialogPoppedUp()
@ -73,7 +73,6 @@ Item {
function init() {
// going to/from sign in/up dialog.
loginDialog.isLogIn = false;
emailField.placeholderText = "Email";
emailField.text = "";
emailField.anchors.top = usernameField.bottom;
@ -353,7 +352,7 @@ Item {
}
UserActivityLogger.logAction("encourageLoginDialog", data);
}
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": signUpBody.linkSteam });
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": false });
}
}
HifiControlsUit.Button {
@ -380,6 +379,54 @@ Item {
signUpBody.signup();
}
}
Item {
id: termsContainer
width: parent.width
height: termsTextMetrics.height
anchors {
top: signUpButton.bottom
horizontalCenter: parent.horizontalCenter
topMargin: 2 * hifi.dimensions.contentSpacing.y
left: parent.left
}
TextMetrics {
id: termsTextMetrics
font: termsText.font
text: signUpBody.termsContainerText
Component.onCompleted: {
// with the link.
termsText.text = qsTr("By signing up, you agree to <a href='https://highfidelity.com/terms'>High Fidelity's Terms of Service</a>")
}
}
HifiStylesUit.InfoItem {
id: termsText
text: signUpBody.termsContainerText
font.family: signUpBody.fontFamily
font.pixelSize: signUpBody.fontSize
font.bold: signUpBody.fontBold
wrapMode: Text.WordWrap
color: hifi.colors.white
linkColor: hifi.colors.blueAccent
lineHeight: 1
lineHeightMode: Text.ProportionalHeight
onLinkActivated: loginDialog.openUrl(link);
Component.onCompleted: {
if (termsTextMetrics.width > root.bannerWidth) {
termsText.width = root.bannerWidth;
termsText.wrapMode = Text.WordWrap;
additionalText.verticalAlignment = Text.AlignLeft;
additionalText.horizontalAlignment = Text.AlignLeft;
termsContainer.height = (termsTextMetrics.width / root.bannerWidth) * termsTextMetrics.height;
termsContainer.anchors.left = buttons.left;
} else {
termsText.anchors.centerIn = termsContainer;
}
}
}
}
}
}
@ -433,14 +480,15 @@ Item {
if (errorString !== "") {
loginErrorMessage.visible = true;
var errorLength = errorString.split(/\r\n|\r|\n/).length;
var errorStringEdited = errorString.replace(/[\n\r]+/g, "\n");
loginErrorMessage.text = errorStringEdited;
loginErrorMessageTextMetrics.text = errorString;
if (loginErrorMessageTextMetrics.width > usernameField.width) {
if (errorLength > 1.0) {
loginErrorMessage.width = root.bannerWidth;
loginErrorMessage.wrapMode = Text.WordWrap;
loginErrorMessage.verticalAlignment = Text.AlignLeft;
loginErrorMessage.horizontalAlignment = Text.AlignLeft;
errorContainer.height = (loginErrorMessageTextMetrics.width / usernameField.width) * loginErrorMessageTextMetrics.height;
errorContainer.height = errorLength * loginErrorMessageTextMetrics.height;
}
errorContainer.anchors.bottom = usernameField.top;
errorContainer.anchors.bottomMargin = hifi.dimensions.contentSpacing.y;

View file

@ -19,6 +19,7 @@ import TabletScriptingInterface 1.0
Item {
id: usernameCollisionBody
clip: true
readonly property string termsContainerText: qsTr("By creating this user profile, you agree to High Fidelity's Terms of Service")
width: root.width
height: root.height
readonly property string fontFamily: "Raleway"
@ -26,13 +27,18 @@ Item {
readonly property int textFieldFontSize: 18
readonly property bool fontBold: true
readonly property bool withSteam: withSteam
property bool withSteam: withSteam
property bool withOculus: withOculus
readonly property bool loginDialogPoppedUp: loginDialog.getLoginDialogPoppedUp()
function create() {
mainTextContainer.visible = false
loginDialog.createAccountFromSteam(textField.text);
if (usernameCollisionBody.withOculus) {
loginDialog.createAccountFromOculus(textField.text);
} else if (usernameCollisionBody.withSteam) {
loginDialog.createAccountFromSteam(textField.text);
}
}
property bool keyboardEnabled: false
@ -90,12 +96,19 @@ Item {
font.family: usernameCollisionBody.fontFamily
font.pixelSize: usernameCollisionBody.fontSize
font.bold: usernameCollisionBody.fontBold
text: qsTr("Your Steam username is not available.");
text: qsTr("");
wrapMode: Text.WordWrap
color: hifi.colors.redAccent
lineHeight: 1
lineHeightMode: Text.ProportionalHeight
horizontalAlignment: Text.AlignHCenter
Component.onCompleted: {
if (usernameCollisionBody.withOculus) {
text = qsTr("Your Oculus username is not available.");
} else if (usernameCollisionBody.withSteam) {
text = qsTr("Your Steam username is not available.");
}
}
}
@ -164,7 +177,8 @@ Item {
fontSize: usernameCollisionBody.fontSize
fontBold: usernameCollisionBody.fontBold
onClicked: {
bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "errorString": "" });
bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": usernameCollisionBody.withSteam,
"withOculus": usernameCollisionBody.withOculus, "errorString": "" });
}
}
HifiControlsUit.Button {
@ -187,6 +201,55 @@ Item {
}
}
}
Item {
id: termsContainer
width: parent.width
height: termsTextMetrics.height
anchors {
top: buttons.bottom
horizontalCenter: parent.horizontalCenter
topMargin: 2 * hifi.dimensions.contentSpacing.y
left: parent.left
leftMargin: (parent.width - buttons.width) / 2
}
TextMetrics {
id: termsTextMetrics
font: termsText.font
text: usernameCollisionBody.termsContainerText
Component.onCompleted: {
// with the link.
termsText.text = qsTr("By creating this user profile, you agree to <a href='https://highfidelity.com/terms'>High Fidelity's Terms of Service</a>")
}
}
HifiStylesUit.InfoItem {
id: termsText
text: usernameCollisionBody.termsContainerText
font.family: usernameCollisionBody.fontFamily
font.pixelSize: usernameCollisionBody.fontSize
font.bold: usernameCollisionBody.fontBold
wrapMode: Text.WordWrap
color: hifi.colors.white
linkColor: hifi.colors.blueAccent
lineHeight: 1
lineHeightMode: Text.ProportionalHeight
onLinkActivated: loginDialog.openUrl(link);
Component.onCompleted: {
if (termsTextMetrics.width > root.bannerWidth) {
termsText.width = root.bannerWidth;
termsText.wrapMode = Text.WordWrap;
additionalText.verticalAlignment = Text.AlignLeft;
additionalText.horizontalAlignment = Text.AlignLeft;
termsContainer.height = (termsTextMetrics.width / root.bannerWidth) * termsTextMetrics.height;
termsContainer.anchors.left = buttons.left;
} else {
termsText.anchors.centerIn = termsContainer;
}
}
}
}
}
Component.onCompleted: {
@ -201,18 +264,25 @@ Item {
target: loginDialog
onHandleCreateCompleted: {
console.log("Create Succeeded");
if (usernameCollisionBody.withSteam) {
if (usernameCollisionBody.withOculus) {
if (usernameCollisionBody.loginDialogPoppedUp) {
var data = {
"action": "user created a profile with Oculus successfully in the username collision screen"
}
UserActivityLogger.logAction("encourageLoginDialog", data);
}
loginDialog.loginThroughOculus();
} else if (usernameCollisionBody.withSteam) {
if (usernameCollisionBody.loginDialogPoppedUp) {
var data = {
"action": "user created a profile with Steam successfully in the username collision screen"
}
UserActivityLogger.logAction("encourageLoginDialog", data);
}
loginDialog.loginThroughSteam();
}
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": usernameCollisionBody.withSteam, "linkSteam": false })
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": usernameCollisionBody.withSteam,
"withOculus": usernameCollisionBody.withOculus, "linkSteam": false, "linkOculus": false })
}
onHandleCreateFailed: {
console.log("Create Failed: " + error)

View file

@ -150,6 +150,6 @@ FocusScope {
Component.onCompleted: {
keyboardTimer.start();
bodyLoader.setSource("LoginDialog/LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": false });
bodyLoader.setSource("LoginDialog/LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": false, "linkOculus": false });
}
}

View file

@ -14,6 +14,8 @@ import QtQuick 2.5
import controlsUit 1.0 as HifiControlsUit
import stylesUit 1.0 as HifiStylesUit
import TabletScriptingInterface 1.0
import "../LoginDialog"
FocusScope {
@ -25,10 +27,9 @@ FocusScope {
width: parent.width
height: parent.height
signal sendToScript(var message);
signal canceled();
property var tabletProxy: Tablet.getTablet("com.highfidelity.interface.tablet.system");
property bool isHMD: false
property bool isHMD: HMD.active
property bool gotoPreviousApp: false;
property bool keyboardEnabled: false
@ -52,6 +53,7 @@ FocusScope {
}
function tryDestroy() {
tabletProxy.gotoHomeScreen();
}
MouseArea {
@ -76,7 +78,7 @@ FocusScope {
interval: 200
onTriggered: {
if (MenuInterface.isOptionChecked("Use 3D Keyboard")) {
if (MenuInterface.isOptionChecked("Use 3D Keyboard") && root.isHMD) {
KeyboardScriptingInterface.raised = true;
}
}
@ -169,11 +171,13 @@ FocusScope {
Component.onDestruction: {
loginKeyboard.raised = false;
KeyboardScriptingInterface.raised = false;
if (root.isHMD) {
KeyboardScriptingInterface.raised = false;
}
}
Component.onCompleted: {
keyboardTimer.start();
bodyLoader.setSource("../LoginDialog/LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": false });
bodyLoader.setSource("../LoginDialog/LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": false, "linkOculus": false });
}
}

View file

@ -120,6 +120,7 @@
#include <plugins/PluginManager.h>
#include <plugins/PluginUtils.h>
#include <plugins/SteamClientPlugin.h>
#include <plugins/OculusPlatformPlugin.h>
#include <plugins/InputConfiguration.h>
#include <RecordingScriptingInterface.h>
#include <render/EngineStats.h>
@ -800,7 +801,6 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
if (auto steamClient = pluginManager->getSteamClientPlugin()) {
steamClient->init();
}
PROFILE_SET_THREAD_NAME("Main Thread");
#if defined(Q_OS_WIN)
@ -2737,6 +2737,7 @@ Application::~Application() {
if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
steamClient->shutdown();
}
DependencyManager::destroy<PluginManager>();
DependencyManager::destroy<CompositorHelper>(); // must be destroyed before the FramebufferCache
@ -4873,6 +4874,10 @@ void Application::idle() {
steamClient->runCallbacks();
}
if (auto oculusPlugin = PluginManager::getInstance()->getOculusPlatformPlugin()) {
oculusPlugin->handleOVREvents();
}
float secondsSinceLastUpdate = (float)_lastTimeUpdated.nsecsElapsed() / NSECS_PER_MSEC / MSECS_PER_SECOND;
_lastTimeUpdated.start();

View file

@ -18,6 +18,7 @@
#include <plugins/PluginManager.h>
#include <plugins/SteamClientPlugin.h>
#include <plugins/OculusPlatformPlugin.h>
#include <shared/GlobalAppProperties.h>
#include <ui/TabletScriptingInterface.h>
#include <UserActivityLogger.h>
@ -109,8 +110,16 @@ bool LoginDialog::isSteamRunning() const {
return steamClient && steamClient->isRunning();
}
bool LoginDialog::isOculusStoreRunning() const {
return qApp->property(hifi::properties::OCULUS_STORE).toBool();
bool LoginDialog::isOculusRunning() const {
auto oculusPlatformPlugin = PluginManager::getInstance()->getOculusPlatformPlugin();
return (oculusPlatformPlugin && oculusPlatformPlugin->isRunning());
}
QString LoginDialog::oculusUserID() const {
if (auto oculusPlatformPlugin = PluginManager::getInstance()->getOculusPlatformPlugin()) {
return oculusPlatformPlugin->getOculusUserID();
}
return "";
}
void LoginDialog::dismissLoginDialog() {
@ -126,6 +135,79 @@ void LoginDialog::login(const QString& username, const QString& password) const
DependencyManager::get<AccountManager>()->requestAccessToken(username, password);
}
void LoginDialog::loginThroughOculus() {
qDebug() << "Attempting to login through Oculus";
if (auto oculusPlatformPlugin = PluginManager::getInstance()->getOculusPlatformPlugin()) {
oculusPlatformPlugin->requestNonceAndUserID([this] (QString nonce, QString oculusID) {
DependencyManager::get<AccountManager>()->requestAccessTokenWithOculus(nonce, oculusID);
});
}
}
void LoginDialog::linkOculus() {
qDebug() << "Attempting to link Oculus account";
if (auto oculusPlatformPlugin = PluginManager::getInstance()->getOculusPlatformPlugin()) {
oculusPlatformPlugin->requestNonceAndUserID([this] (QString nonce, QString oculusID) {
if (nonce.isEmpty() || oculusID.isEmpty()) {
emit handleLoginFailed();
return;
}
JSONCallbackParameters callbackParams;
callbackParams.callbackReceiver = this;
callbackParams.jsonCallbackMethod = "linkCompleted";
callbackParams.errorCallbackMethod = "linkFailed";
const QString LINK_OCULUS_PATH = "api/v1/user/oculus/link";
QJsonObject payload;
payload["oculus_nonce"] = nonce;
payload["oculus_id"] = oculusID;
auto accountManager = DependencyManager::get<AccountManager>();
accountManager->sendRequest(LINK_OCULUS_PATH, AccountManagerAuth::Required,
QNetworkAccessManager::PostOperation, callbackParams,
QJsonDocument(payload).toJson());
});
}
}
void LoginDialog::createAccountFromOculus(QString email, QString username, QString password) {
qDebug() << "Attempting to create account from Oculus info";
if (auto oculusPlatformPlugin = PluginManager::getInstance()->getOculusPlatformPlugin()) {
oculusPlatformPlugin->requestNonceAndUserID([this, email, username, password] (QString nonce, QString oculusID) {
if (nonce.isEmpty() || oculusID.isEmpty()) {
emit handleLoginFailed();
return;
}
JSONCallbackParameters callbackParams;
callbackParams.callbackReceiver = this;
callbackParams.jsonCallbackMethod = "createCompleted";
callbackParams.errorCallbackMethod = "createFailed";
const QString CREATE_ACCOUNT_FROM_OCULUS_PATH = "api/v1/user/oculus/create";
QJsonObject payload;
payload["oculus_nonce"] = nonce;
payload["oculus_id"] = oculusID;
if (!email.isEmpty()) {
payload["email"] = email;
}
if (!username.isEmpty()) {
payload["username"] = username;
}
if (!password.isEmpty()) {
payload["password"] = password;
}
auto accountManager = DependencyManager::get<AccountManager>();
accountManager->sendRequest(CREATE_ACCOUNT_FROM_OCULUS_PATH, AccountManagerAuth::None,
QNetworkAccessManager::PostOperation, callbackParams,
QJsonDocument(payload).toJson());
});
}
}
void LoginDialog::loginThroughSteam() {
qDebug() << "Attempting to login through Steam";
if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
@ -157,7 +239,7 @@ void LoginDialog::linkSteam() {
const QString LINK_STEAM_PATH = "api/v1/user/steam/link";
QJsonObject payload;
payload.insert("steam_auth_ticket", QJsonValue::fromVariant(QVariant(ticket)));
payload["steam_auth_ticket"] = QJsonValue::fromVariant(QVariant(ticket));
auto accountManager = DependencyManager::get<AccountManager>();
accountManager->sendRequest(LINK_STEAM_PATH, AccountManagerAuth::Required,
@ -184,9 +266,9 @@ void LoginDialog::createAccountFromSteam(QString username) {
const QString CREATE_ACCOUNT_FROM_STEAM_PATH = "api/v1/user/steam/create";
QJsonObject payload;
payload.insert("steam_auth_ticket", QJsonValue::fromVariant(QVariant(ticket)));
payload["steam_auth_ticket"] = QJsonValue::fromVariant(QVariant(ticket));
if (!username.isEmpty()) {
payload.insert("username", QJsonValue::fromVariant(QVariant(username)));
payload["username"] = username;
}
auto accountManager = DependencyManager::get<AccountManager>();
@ -214,6 +296,45 @@ void LoginDialog::createCompleted(QNetworkReply* reply) {
}
void LoginDialog::createFailed(QNetworkReply* reply) {
if (isOculusRunning()) {
auto replyData = reply->readAll();
QJsonParseError parseError;
auto doc = QJsonDocument::fromJson(replyData, &parseError);
if (parseError.error != QJsonParseError::NoError) {
emit handleCreateFailed(reply->errorString());
return;
}
auto data = doc["data"];
auto error = data["error"];
auto oculusError = data["oculus"];
auto user = error["username"].toArray();
auto uid = error["uid"].toArray();
auto email = error["email"].toArray();
auto password = error["password"].toArray();
QString reply;
if (uid[0].isString()) {
emit handleCreateFailed("Oculus ID " + uid[0].toString() + ".");
return;
}
if (user[0].isString()) {
reply = "Username " + user[0].toString() + ".";
}
if (email[0].isString()) {
reply.append((!reply.isEmpty()) ? "\n" : "");
reply.append("Email " + email[0].toString() + ".");
}
if (password[0].isString()) {
reply.append((!reply.isEmpty()) ? "\n" : "");
reply.append("Password " + password[0].toString() + ".");
}
if (!oculusError.isNull() && !oculusError.isUndefined()) {
emit handleCreateFailed("Could not verify token with Oculus. Please try again.");
return;
} else {
emit handleCreateFailed(reply);
return;
}
}
emit handleCreateFailed(reply->errorString());
}

View file

@ -22,7 +22,6 @@ extern const QUrl OVERLAY_LOGIN_DIALOG;
class LoginDialog : public OffscreenQmlDialog {
Q_OBJECT
Q_PROPERTY(bool isLogIn READ getIsLogIn WRITE setIsLogIn)
HIFI_QML_DECL
public:
@ -67,24 +66,23 @@ protected slots:
Q_INVOKABLE void dismissLoginDialog();
Q_INVOKABLE bool isSteamRunning() const;
Q_INVOKABLE bool isOculusStoreRunning() const;
Q_INVOKABLE bool isOculusRunning() const;
Q_INVOKABLE QString oculusUserID() const;
Q_INVOKABLE void login(const QString& username, const QString& password) const;
Q_INVOKABLE void loginThroughSteam();
Q_INVOKABLE void linkSteam();
Q_INVOKABLE void createAccountFromSteam(QString username = QString());
Q_INVOKABLE void loginThroughOculus();
Q_INVOKABLE void linkOculus();
Q_INVOKABLE void createAccountFromOculus(QString email = QString(), QString username = QString(), QString password = QString());
Q_INVOKABLE void signup(const QString& email, const QString& username, const QString& password);
Q_INVOKABLE void openUrl(const QString& url) const;
Q_INVOKABLE bool getLoginDialogPoppedUp() const;
private:
bool getIsLogIn() const { return _isLogIn; }
void setIsLogIn(const bool isLogIn) { _isLogIn = isLogIn; }
bool _isLogIn{ false };
};
#endif // hifi_LoginDialog_h

View file

@ -31,6 +31,8 @@ public:
virtual void compositeExtra() override;
virtual void pluginUpdate() override {};
protected:
mutable bool _isThrottled = false;

View file

@ -20,6 +20,7 @@ public:
QImage getScreenshot(float aspectRatio = 0.0f) const override;
QImage getSecondaryCameraScreenshot() const override;
void copyTextureToQuickFramebuffer(NetworkTexturePointer source, QOpenGLFramebufferObject* target, GLsync* fenceSync) override {};
void pluginUpdate() override {};
private:
static const QString NAME;
};

View file

@ -46,6 +46,8 @@ public:
virtual bool onDisplayTextureReset() override { _clearPreviewFlag = true; return true; };
void pluginUpdate() override {};
signals:
void hmdMountedChanged();
void hmdVisibleChanged(bool visible);

View file

@ -28,6 +28,8 @@ public:
// to the HMD plugins.
//virtual glm::mat4 getEyeToHeadTransform(Eye eye) const override;
virtual void pluginUpdate() override {};
protected:
virtual bool internalActivate() override;
virtual void internalDeactivate() override;

View file

@ -588,6 +588,29 @@ void AccountManager::requestAccessTokenWithSteam(QByteArray authSessionTicket) {
connect(requestReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(requestAccessTokenError(QNetworkReply::NetworkError)));
}
void AccountManager::requestAccessTokenWithOculus(const QString& nonce, const QString &oculusID) {
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkRequest request;
request.setHeader(QNetworkRequest::UserAgentHeader, _userAgentGetter());
QUrl grantURL = _authURL;
grantURL.setPath("/oauth/token");
QByteArray postData;
postData.append("grant_type=password&");
postData.append("oculus_nonce=" + nonce + "&");
postData.append("oculus_id=" + oculusID + "&");
postData.append("scope=" + ACCOUNT_MANAGER_REQUESTED_SCOPE);
request.setUrl(grantURL);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
QNetworkReply* requestReply = networkAccessManager.post(request, postData);
connect(requestReply, &QNetworkReply::finished, this, &AccountManager::requestAccessTokenFinished);
connect(requestReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(requestAccessTokenError(QNetworkReply::NetworkError)));
}
void AccountManager::refreshAccessToken() {
// we can't refresh our access token if we don't have a refresh token, so check for that first

View file

@ -106,6 +106,7 @@ public:
public slots:
void requestAccessToken(const QString& login, const QString& password);
void requestAccessTokenWithSteam(QByteArray authSessionTicket);
void requestAccessTokenWithOculus(const QString& nonce, const QString& oculusID);
void requestAccessTokenWithAuthCode(const QString& authCode,
const QString& clientId,
const QString& clientSecret,

View file

@ -217,6 +217,9 @@ public:
static const QString& MENU_PATH();
// for updating plugin-related commands. Mimics the input plugin.
virtual void pluginUpdate() = 0;
signals:
void recommendedFramebufferSizeChanged(const QSize& size);
void resetSensorsRequested();

View file

@ -21,6 +21,7 @@ class DisplayPlugin;
class InputPlugin;
class CodecPlugin;
class SteamClientPlugin;
class OculusPlatformPlugin;
class Plugin;
class PluginContainer;
class PluginManager;
@ -35,4 +36,5 @@ using CodecPluginPointer = std::shared_ptr<CodecPlugin>;
using CodecPluginList = std::vector<CodecPluginPointer>;
using CodecPluginProvider = std::function<CodecPluginList()>;
using SteamClientPluginPointer = std::shared_ptr<SteamClientPlugin>;
using OculusPlatformPluginPointer = std::shared_ptr<OculusPlatformPlugin>;
using InputPluginSettingsPersister = std::function<void(const InputPluginList&)>;

View file

@ -0,0 +1,28 @@
//
// Created by Wayne Chen on 2018/12/20
// Copyright 2018 High Fidelity Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2-0.html
//
#pragma once
#include <QtCore/QString>
#include <functional>
using NonceUserIDCallback = std::function<void(QString, QString)>;
class OculusPlatformPlugin {
public:
virtual ~OculusPlatformPlugin() = default;
virtual QString getName() const = 0;
virtual QString getOculusUserID() const = 0;
virtual bool isRunning() const = 0;
virtual void requestNonceAndUserID(NonceUserIDCallback callback) = 0;
virtual void handleOVREvents() = 0;
};

View file

@ -188,6 +188,22 @@ const SteamClientPluginPointer PluginManager::getSteamClientPlugin() {
return steamClientPlugin;
}
const OculusPlatformPluginPointer PluginManager::getOculusPlatformPlugin() {
static OculusPlatformPluginPointer oculusPlatformPlugin;
static std::once_flag once;
std::call_once(once, [&] {
// Now grab the dynamic plugins
for (auto loader : getLoadedPlugins()) {
OculusPlatformProvider* oculusPlatformProvider = qobject_cast<OculusPlatformProvider*>(loader->instance());
if (oculusPlatformProvider) {
oculusPlatformPlugin = oculusPlatformProvider->getOculusPlatformPlugin();
break;
}
}
});
return oculusPlatformPlugin;
}
const DisplayPluginList& PluginManager::getDisplayPlugins() {
static std::once_flag once;
static auto deviceAddedCallback = [](QString deviceName) {

View file

@ -27,6 +27,7 @@ public:
const InputPluginList& getInputPlugins();
const CodecPluginList& getCodecPlugins();
const SteamClientPluginPointer getSteamClientPlugin();
const OculusPlatformPluginPointer getOculusPlatformPlugin();
DisplayPluginList getPreferredDisplayPlugins();
void setPreferredDisplayPlugins(const QStringList& displays);

View file

@ -51,5 +51,13 @@ public:
virtual SteamClientPluginPointer getSteamClientPlugin() = 0;
};
class OculusPlatformProvider {
public:
virtual OculusPlatformPluginPointer getOculusPlatformPlugin() = 0;
};
#define SteamClientProvider_iid "com.highfidelity.plugins.steamclient"
Q_DECLARE_INTERFACE(SteamClientProvider, SteamClientProvider_iid)
#define OculusPlatformProvider_iid "com.highfidelity.plugins.oculusplatform"
Q_DECLARE_INTERFACE(OculusPlatformProvider, OculusPlatformProvider_iid)

View file

@ -12,6 +12,7 @@
#include <display-plugins/CompositorHelper.h>
#include <gpu/Frame.h>
#include <gl/Config.h>
#include <shared/GlobalAppProperties.h>
#include "OculusHelpers.h"
@ -30,7 +31,7 @@ bool OculusBaseDisplayPlugin::beginFrameRender(uint32_t frameIndex) {
return false;
}
if (ovr::quitRequested(status) || ovr::displayLost(status) || !ovr::handleOVREvents()) {
if (ovr::quitRequested(status) || ovr::displayLost(status)) {
QMetaObject::invokeMethod(qApp, "quit");
return false;
}

View file

@ -13,6 +13,9 @@
#include <OVR_CAPI_GL.h>
#define OVRPL_DISABLED
#include <OVR_Platform.h>
class OculusBaseDisplayPlugin : public HmdDisplayPlugin {
using Parent = HmdDisplayPlugin;
public:
@ -30,7 +33,7 @@ public:
QRectF getPlayAreaRect() override;
QVector<glm::vec3> getSensorPositions() override;
protected:
void customizeContext() override;
void uncustomizeContext() override;

View file

@ -296,34 +296,3 @@ controller::Pose hifi::ovr::toControllerPose(ovrHandType hand,
pose.valid = true;
return pose;
}
bool hifi::ovr::handleOVREvents() {
#ifdef OCULUS_APP_ID
if (qApp->property(hifi::properties::OCULUS_STORE).toBool()) {
// pop messages to see if we got a return for an entitlement check
ovrMessageHandle message = ovr_PopMessage();
while (message) {
switch (ovr_Message_GetType(message)) {
case ovrMessage_Entitlement_GetIsViewerEntitled: {
if (!ovr_Message_IsError(message)) {
// this viewer is entitled, no need to flag anything
qCDebug(oculusLog) << "Oculus Platform entitlement check succeeded, proceeding normally";
} else {
// we failed the entitlement check, quit
qCDebug(oculusLog) << "Oculus Platform entitlement check failed, app will now quit" << OCULUS_APP_ID;
return false;
}
}
}
// free the message handle to cleanup and not leak
ovr_FreeMessage(message);
// pop the next message to check, if there is one
message = ovr_PopMessage();
}
}
#endif
return true;
}

View file

@ -30,7 +30,6 @@ struct ovr {
static ovrSessionStatus getStatus(ovrResult& result);
static ovrTrackingState getTrackingState(double absTime = 0.0, ovrBool latencyMarker = ovrFalse);
static QString getError();
static bool handleOVREvents();
static inline bool quitRequested() { return quitRequested(getStatus()); }
static inline bool reorientRequested() { return reorientRequested(getStatus()); }

View file

@ -0,0 +1,109 @@
//
// Created by Wayne Chen on 2019/01/08
// Copyright 2019 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "OculusPlatformPlugin.h"
#include <shared/GlobalAppProperties.h>
#include <QMetaObject>
#include "OculusHelpers.h"
QString OculusAPIPlugin::NAME { "Oculus Rift" };
OculusAPIPlugin::OculusAPIPlugin() {
_session = hifi::ovr::acquireRenderSession();
}
OculusAPIPlugin::~OculusAPIPlugin() {
hifi::ovr::releaseRenderSession(_session);
}
bool OculusAPIPlugin::isRunning() const {
return (qApp->property(hifi::properties::OCULUS_STORE).toBool());
}
void OculusAPIPlugin::requestNonceAndUserID(NonceUserIDCallback callback) {
#ifdef OCULUS_APP_ID
_nonceUserIDCallback = callback;
ovr_User_GetUserProof();
ovr_User_GetLoggedInUser();
#endif
}
void OculusAPIPlugin::handleOVREvents() {
#ifdef OCULUS_APP_ID
if (qApp->property(hifi::properties::OCULUS_STORE).toBool()) {
// pop messages to see if we got a return for an entitlement check
ovrMessageHandle message { nullptr };
// pop the next message to check, if there is one
while ((message = ovr_PopMessage())) {
switch (ovr_Message_GetType(message)) {
case ovrMessage_Entitlement_GetIsViewerEntitled: {
if (!ovr_Message_IsError(message)) {
// this viewer is entitled, no need to flag anything
qCDebug(oculusLog) << "Oculus Platform entitlement check succeeded, proceeding normally";
} else {
// we failed the entitlement check, quit
qCDebug(oculusLog) << "Oculus Platform entitlement check failed, app will now quit" << OCULUS_APP_ID;
QMetaObject::invokeMethod(qApp, "quit");
}
break;
}
case ovrMessage_User_Get: {
if (!ovr_Message_IsError(message)) {
qCDebug(oculusLog) << "Oculus Platform user retrieval succeeded";
ovrUserHandle user = ovr_Message_GetUser(message);
_user = ovr_User_GetOculusID(user);
// went all the way through the `requestNonceAndUserID()` pipeline successfully.
} else {
qCDebug(oculusLog) << "Oculus Platform user retrieval failed" << QString(ovr_Error_GetMessage(ovr_Message_GetError(message)));
// emit the signal so we don't hang for it anywhere else.
_user = "";
}
break;
}
case ovrMessage_User_GetLoggedInUser: {
if (!ovr_Message_IsError(message)) {
ovrUserHandle user = ovr_Message_GetUser(message);
_userID = ovr_User_GetID(user);
ovr_User_Get(_userID);
} else {
qCDebug(oculusLog) << "Oculus Platform user ID retrieval failed" << QString(ovr_Error_GetMessage(ovr_Message_GetError(message)));
// emit the signal so we don't hang for it anywhere else.
}
_userIDChanged = true;
break;
}
case ovrMessage_User_GetUserProof: {
if (!ovr_Message_IsError(message)) {
ovrUserProofHandle userProof = ovr_Message_GetUserProof(message);
_nonce = ovr_UserProof_GetNonce(userProof);
qCDebug(oculusLog) << "Oculus Platform nonce retrieval succeeded: " << _nonce;
} else {
qCDebug(oculusLog) << "Oculus Platform nonce retrieval failed" << QString(ovr_Error_GetMessage(ovr_Message_GetError(message)));
_nonce = "";
// emit the signal so we don't hang for it anywhere else.
}
_nonceChanged = true;
break;
}
}
if (_nonceChanged && _userIDChanged) {
_nonceUserIDCallback(_nonce, QString::number(_userID));
_nonceChanged = _userIDChanged = false;
}
// free the message handle to cleanup and not leak
ovr_FreeMessage(message);
}
}
#endif
}

View file

@ -0,0 +1,39 @@
//
// Created by Wayne Chen on 2019/01/08
// Copyright 2019 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#pragma once
#include <plugins/OculusPlatformPlugin.h>
#include <OVR_CAPI_GL.h>
#define OVRPL_DISABLED
#include <OVR_Platform.h>
class OculusAPIPlugin : public OculusPlatformPlugin {
public:
OculusAPIPlugin();
virtual ~OculusAPIPlugin();
QString getName() const { return NAME; }
QString getOculusUserID() const { return _user; };
bool isRunning() const;
virtual void requestNonceAndUserID(NonceUserIDCallback callback);
virtual void handleOVREvents();
private:
static QString NAME;
NonceUserIDCallback _nonceUserIDCallback;
QString _nonce;
bool _nonceChanged{ false };
bool _userIDChanged{ false };
QString _user;
ovrID _userID;
ovrSession _session;
};

View file

@ -18,15 +18,18 @@
#include "OculusDisplayPlugin.h"
#include "OculusDebugDisplayPlugin.h"
#include "OculusPlatformPlugin.h"
#include "OculusControllerManager.h"
class OculusProvider : public QObject, public DisplayProvider, InputProvider
class OculusProvider : public QObject, public DisplayProvider, InputProvider, OculusPlatformProvider
{
Q_OBJECT
Q_PLUGIN_METADATA(IID DisplayProvider_iid FILE "oculus.json")
Q_INTERFACES(DisplayProvider)
Q_PLUGIN_METADATA(IID InputProvider_iid FILE "oculus.json")
Q_INTERFACES(InputProvider)
Q_PLUGIN_METADATA(IID OculusPlatformProvider_iid FILE "oculus.json")
Q_INTERFACES(OculusPlatformProvider)
public:
OculusProvider(QObject* parent = nullptr) : QObject(parent) {}
@ -62,6 +65,15 @@ public:
return _inputPlugins;
}
virtual OculusPlatformPluginPointer getOculusPlatformPlugin() override {
static std::once_flag once;
std::call_once(once, [&] {
_oculusPlatformPlugin = std::make_shared<OculusAPIPlugin>();
});
return _oculusPlatformPlugin;
}
virtual void destroyInputPlugins() override {
_inputPlugins.clear();
}
@ -73,6 +85,7 @@ public:
private:
DisplayPluginList _displayPlugins;
InputPluginList _inputPlugins;
OculusPlatformPluginPointer _oculusPlatformPlugin;
};
#include "OculusProvider.moc"