History

Merge pull request #14727 from wayne-chen/oculusLoginFeature

Jeff Clinton committed 7 years ago

Commit f78fdff2 parents 17b8f65 1c6521430 files · +983 −215Browse files

Unified · Split

30 files
  1. interface/resources/qml/LoginDialog.qml +1 −1
  2. interface/resources/qml/LoginDialog/CompleteProfileBody.qml +300 −69
  3. interface/resources/qml/LoginDialog/LinkAccountBody.qml +30 −57
  4. interface/resources/qml/LoginDialog/LoggingInBody.qml +114 −18
  5. interface/resources/qml/LoginDialog/SignUpBody.qml +54 −6
  6. interface/resources/qml/LoginDialog/UsernameCollisionBody.qml +78 −8
  7. interface/resources/qml/OverlayLoginDialog.qml +1 −1
  8. interface/resources/qml/dialogs/TabletLoginDialog.qml +10 −6
  9. interface/src/Application.cpp +6 −1
  10. interface/src/ui/LoginDialog.cpp +126 −5
  11. interface/src/ui/LoginDialog.h +6 −8
  12. libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h +2 −0
  13. libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h +1 −0
  14. libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h +2 −0
  15. libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.h +2 −0
  16. libraries/networking/src/AccountManager.cpp +23 −0
  17. libraries/networking/src/AccountManager.h +1 −0
  18. libraries/plugins/src/plugins/DisplayPlugin.h +3 −0
  19. libraries/plugins/src/plugins/Forward.h +2 −0
  20. libraries/plugins/src/plugins/OculusPlatformPlugin.h +28 −0
  21. libraries/plugins/src/plugins/PluginManager.cpp +16 −0
  22. libraries/plugins/src/plugins/PluginManager.h +1 −0
  23. libraries/plugins/src/plugins/RuntimePlugin.h +8 −0
  24. plugins/oculus/src/OculusBaseDisplayPlugin.cpp +2 −1
  25. plugins/oculus/src/OculusBaseDisplayPlugin.h +4 −1
  26. plugins/oculus/src/OculusHelpers.cpp +0 −31
  27. plugins/oculus/src/OculusHelpers.h +0 −1
  28. plugins/oculus/src/OculusPlatformPlugin.cpp +109 −0
  29. plugins/oculus/src/OculusPlatformPlugin.h +39 −0
  30. plugins/oculus/src/OculusProvider.cpp +14 −1
interface/resources/qml/LoginDialog.qml+1−1
@@ -120,6 +120,6 @@ FocusScope { · 119 unmodified lines
120 }120 }
121 121
122 Component.onCompleted: {122 Component.onCompleted: {
123 bodyLoader.setSource("LoginDialog/LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": false });123 bodyLoader.setSource("LoginDialog/LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": false, "linkOculus": false });
124 }124 }
125}125}
interface/resources/qml/LoginDialog/CompleteProfileBody.qml+300−69
@@ -22,11 +22,16 @@ Item { · 21 unmodified lines
22 width: root.width22 width: root.width
23 height: root.height23 height: root.height
24 readonly property string termsContainerText: qsTr("By creating this user profile, you agree to High Fidelity's Terms of Service")24 readonly property string termsContainerText: qsTr("By creating this user profile, you agree to High Fidelity's Terms of Service")
25 readonly property string termsContainerOculusText: qsTr("By signing up, you agree to High Fidelity's Terms of Service")
26 readonly property int textFieldHeight: 31
25 readonly property string fontFamily: "Raleway"27 readonly property string fontFamily: "Raleway"
26 readonly property int fontSize: 1528 readonly property int fontSize: 15
27 readonly property bool fontBold: true29 readonly property bool fontBold: true
30 readonly property int textFieldFontSize: 18
31 readonly property var passwordImageRatio: 16 / 23
28 32
29 readonly property bool withSteam: withSteam33 property bool withOculus: withOculus
34 property bool withSteam: withSteam
30 property string errorString: errorString35 property string errorString: errorString
31 36
32 readonly property bool loginDialogPoppedUp: loginDialog.getLoginDialogPoppedUp()37 readonly property bool loginDialogPoppedUp: loginDialog.getLoginDialogPoppedUp()
@@ -61,15 +66,20 @@ Item { · 28 unmodified lines
61 66
62 Item {67 Item {
63 id: contentItem68 id: contentItem
64 anchors.fill: parent69 width: parent.width
70 height: errorContainer.height + fields.height + buttons.height + additionalTextContainer.height +
71 termsContainer.height
72 anchors.top: parent.top
73 anchors.topMargin: root.bannerHeight + 0.25 * parent.height
74 anchors.left: parent.left
65 75
66 Item {76 Item {
67 id: errorContainer77 id: errorContainer
68 width: parent.width78 width: root.bannerWidth
69 height: loginErrorMessageTextMetrics.height79 height: loginErrorMessageTextMetrics.height
70 anchors {80 anchors {
71 bottom: buttons.top;81 bottom: completeProfileBody.withOculus ? fields.top : buttons.top;
72 bottomMargin: hifi.dimensions.contentSpacing.y;82 bottomMargin: 1.5 * hifi.dimensions.contentSpacing.y;
73 left: buttons.left;83 left: buttons.left;
74 }84 }
75 TextMetrics {85 TextMetrics {
@@ -79,8 +89,8 @@ Item { · 3 unmodified lines
79 }89 }
80 Text {90 Text {
81 id: loginErrorMessage;91 id: loginErrorMessage;
82 width: root.bannerWidth
83 color: "red";92 color: "red";
93 width: root.bannerWidth;
84 font.family: completeProfileBody.fontFamily94 font.family: completeProfileBody.fontFamily
85 font.pixelSize: 1895 font.pixelSize: 18
86 font.bold: completeProfileBody.fontBold96 font.bold: completeProfileBody.fontBold
@@ -88,13 +98,196 @@ Item { · 1 unmodified line
88 horizontalAlignment: Text.AlignHCenter98 horizontalAlignment: Text.AlignHCenter
89 text: completeProfileBody.errorString99 text: completeProfileBody.errorString
90 visible: true100 visible: true
101 onTextChanged: {
102 mainContainer.recalculateErrorMessage();
103 }
104 Component.onCompleted: {
105 mainContainer.recalculateErrorMessage();
106 }
107 }
108 }
109
110 Item {
111 id: fields
112 width: root.bannerWidth
113 height: 3 * completeProfileBody.textFieldHeight + 2 * hifi.dimensions.contentSpacing.y
114 visible: completeProfileBody.withOculus
115 anchors {
116 left: parent.left
117 leftMargin: (parent.width - root.bannerWidth) / 2
118 bottom: buttons.top
119 bottomMargin: hifi.dimensions.contentSpacing.y
120 }
121
122 HifiControlsUit.TextField {
123 id: usernameField
124 width: root.bannerWidth
125 height: completeProfileBody.textFieldHeight
126 placeholderText: "Username"
127 font.pixelSize: completeProfileBody.textFieldFontSize
128 styleRenderType: Text.QtRendering
129 anchors {
130 top: parent.top
131 }
132 Keys.onPressed: {
133 if (!usernameField.visible) {
134 return;
135 }
136 switch (event.key) {
137 case Qt.Key_Tab:
138 event.accepted = true;
139 if (event.modifiers === Qt.ShiftModifier) {
140 passwordField.focus = true;
141 } else {
142 emailField.focus = true;
143 }
144 break;
145 case Qt.Key_Backtab:
146 event.accepted = true;
147 passwordField.focus = true;
148 break;
149 case Qt.Key_Enter:
150 case Qt.Key_Return:
151 event.accepted = true;
152 loginDialog.createAccountFromOculus(emailField.text, usernameField.text, passwordField.text);
153 bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": completeProfileBody.withSteam,
154 "linkSteam": false, "withOculus": completeProfileBody.withOculus, "linkOculus": false, "createOculus": true });
155 break;
156 }
157 }
158 onFocusChanged: {
159 root.text = "";
160 if (focus) {
161 root.isPassword = false;
162 }
163 }
164 Component.onCompleted: {
165 var userID = "";
166 if (completeProfileBody.withOculus) {
167 userID = loginDialog.oculusUserID();
168 }
169 usernameField.text = userID;
170 }
171 }
172 HifiControlsUit.TextField {
173 id: emailField
174 width: root.bannerWidth
175 height: completeProfileBody.textFieldHeight
176 anchors {
177 top: usernameField.bottom
178 topMargin: hifi.dimensions.contentSpacing.y
179 }
180 placeholderText: "Email"
181 font.pixelSize: completeProfileBody.textFieldFontSize
182 styleRenderType: Text.QtRendering
183 activeFocusOnPress: true
184 Keys.onPressed: {
185 switch (event.key) {
186 case Qt.Key_Tab:
187 event.accepted = true;
188 if (event.modifiers === Qt.ShiftModifier) {
189 usernameField.focus = true;
190 } else {
191 passwordField.focus = true;
192 }
193 break;
194 case Qt.Key_Backtab:
195 event.accepted = true;
196 usernameField.focus = true;
197 break;
198 case Qt.Key_Enter:
199 case Qt.Key_Return:
200 event.accepted = true;
201 loginDialog.createAccountFromOculus(emailField.text, usernameField.text, passwordField.text);
202 bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": completeProfileBody.withSteam,
203 "linkSteam": false, "withOculus": completeProfileBody.withOculus, "linkOculus": false, "createOculus": true });
204 break;
205 }
206 }
207 onFocusChanged: {
208 root.text = "";
209 if (focus) {
210 root.isPassword = false;
211 }
212 }
91 }213 }
92 Component.onCompleted: {214 HifiControlsUit.TextField {
93 if (loginErrorMessageTextMetrics.width > root.bannerWidth && root.isTablet) {215 id: passwordField
94 loginErrorMessage.wrapMode = Text.WordWrap;216 width: root.bannerWidth
95 loginErrorMessage.verticalAlignment = Text.AlignLeft;217 height: completeProfileBody.textFieldHeight
96 loginErrorMessage.horizontalAlignment = Text.AlignLeft;218 placeholderText: "Password (optional)"
97 errorContainer.height = 3 * loginErrorMessageTextMetrics.height;219 font.pixelSize: completeProfileBody.textFieldFontSize
220 styleRenderType: Text.QtRendering
221 activeFocusOnPress: true
222 echoMode: passwordFieldMouseArea.showPassword ? TextInput.Normal : TextInput.Password
223 anchors {
224 top: emailField.bottom
225 topMargin: hifi.dimensions.contentSpacing.y
226 }
227
228 onFocusChanged: {
229 root.text = "";
230 root.isPassword = focus;
231 }
232
233 Item {
234 id: showPasswordContainer
235 z: 10
236 // width + image's rightMargin
237 width: showPasswordImage.width + 8
238 height: parent.height
239 anchors {
240 right: parent.right
241 }
242
243 Image {
244 id: showPasswordImage
245 width: passwordField.height * passwordImageRatio
246 height: passwordField.height * passwordImageRatio
247 anchors {
248 right: parent.right
249 rightMargin: 8
250 top: parent.top
251 topMargin: passwordFieldMouseArea.showPassword ? 6 : 8
252 bottom: parent.bottom
253 bottomMargin: passwordFieldMouseArea.showPassword ? 5 : 8
254 }
255 source: passwordFieldMouseArea.showPassword ? "../../images/eyeClosed.svg" : "../../images/eyeOpen.svg"
256 MouseArea {
257 id: passwordFieldMouseArea
258 anchors.fill: parent
259 acceptedButtons: Qt.LeftButton
260 property bool showPassword: false
261 onClicked: {
262 showPassword = !showPassword;
263 }
264 }
265 }
266 }
267 Keys.onPressed: {
268 switch (event.key) {
269 case Qt.Key_Tab:
270 event.accepted = true;
271 if (event.modifiers === Qt.ShiftModifier) {
272 emailField.focus = true;
273 } else if (usernameField.visible) {
274 usernameField.focus = true;
275 } else {
276 emailField.focus = true;
277 }
278 break;
279 case Qt.Key_Backtab:
280 event.accepted = true;
281 emailField.focus = true;
282 break;
283 case Qt.Key_Enter:
284 case Qt.Key_Return:
285 event.accepted = true;
286 loginDialog.createAccountFromOculus(emailField.text, usernameField.text, passwordField.text);
287 bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": completeProfileBody.withSteam,
288 "linkSteam": false, "withOculus": completeProfileBody.withOculus, "linkOculus": false, "createOculus": true });
289 break;
290 }
98 }291 }
99 }292 }
100 }293 }
@@ -105,7 +298,7 @@ Item { · 4 unmodified lines
105 height: d.minHeightButton298 height: d.minHeightButton
106 anchors {299 anchors {
107 top: parent.top300 top: parent.top
108 topMargin: (parent.height - additionalTextContainer.height) / 2 - hifi.dimensions.contentSpacing.y301 topMargin: (parent.height - additionalTextContainer.height + fields.height) / 2 - hifi.dimensions.contentSpacing.y
109 left: parent.left302 left: parent.left
110 leftMargin: (parent.width - root.bannerWidth) / 2303 leftMargin: (parent.width - root.bannerWidth) / 2
111 }304 }
@@ -144,7 +337,7 @@ Item { · 32 unmodified lines
144 width: (parent.width - hifi.dimensions.contentSpacing.x) / 2337 width: (parent.width - hifi.dimensions.contentSpacing.x) / 2
145 height: d.minHeightButton338 height: d.minHeightButton
146 339
147 text: qsTr("Create your profile")340 text: completeProfileBody.withOculus ? qsTr("Sign Up") : qsTr("Create your profile")
148 color: hifi.buttons.blue341 color: hifi.buttons.blue
149 342
150 fontFamily: completeProfileBody.fontFamily343 fontFamily: completeProfileBody.fontFamily
@@ -158,116 +351,149 @@ Item { · 7 unmodified lines
158 UserActivityLogger.logAction("encourageLoginDialog", data);351 UserActivityLogger.logAction("encourageLoginDialog", data);
159 }352 }
160 loginErrorMessage.visible = false;353 loginErrorMessage.visible = false;
161 loginDialog.createAccountFromSteam();354 if (completeProfileBody.withOculus) {
355 loginDialog.createAccountFromOculus(emailField.text, usernameField.text, passwordField.text);
356 bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": completeProfileBody.withSteam,
357 "linkSteam": false, "withOculus": completeProfileBody.withOculus, "linkOculus": false, "createOculus": true });
358 } else if (completeProfileBody.withSteam) {
359 loginDialog.createAccountFromSteam();
360 }
162 }361 }
163 }362 }
164 }363 }
165 364
166 Item {365 Item {
167 id: additionalTextContainer366 id: termsContainer
168 width: parent.width367 width: parent.width
169 height: additionalTextMetrics.height368 height: termsTextMetrics.height
170 anchors {369 anchors {
171 top: buttons.bottom370 top: buttons.bottom
172 horizontalCenter: parent.horizontalCenter371 horizontalCenter: parent.horizontalCenter
173 topMargin: hifi.dimensions.contentSpacing.y372 topMargin: hifi.dimensions.contentSpacing.y
174 left: parent.left373 left: parent.left
175 }374 }
176
177 TextMetrics {375 TextMetrics {
178 id: additionalTextMetrics376 id: termsTextMetrics
179 font: additionalText.font377 font: termsText.font
180 text: "Already have a High Fidelity profile? Link to an existing profile here."378 text: completeProfileBody.withOculus ? completeProfileBody.termsContainerOculusText : completeProfileBody.termsContainerText
379 Component.onCompleted: {
380 // with the link.
381 if (completeProfileBody.withOculus) {
382 termsText.text = qsTr("By signing up, you agree to <a href='https://highfidelity.com/terms'>High Fidelity's Terms of Service</a>")
383 } else {
384 termsText.text = qsTr("By creating this user profile, you agree to <a href='https://highfidelity.com/terms'>High Fidelity's Terms of Service</a>")
385 }
386 }
181 }387 }
182 388
183 HifiStylesUit.ShortcutText {389 HifiStylesUit.InfoItem {
184 id: additionalText390 id: termsText
185 text: "<a href='https://fake.link'>Already have a High Fidelity profile? Link to an existing profile here.</a>"391 text: completeProfileBody.withOculus ? completeProfileBody.termsContainerOculusText : completeProfileBody.termsContainerText
186
187 font.family: completeProfileBody.fontFamily392 font.family: completeProfileBody.fontFamily
188 font.pixelSize: completeProfileBody.fontSize393 font.pixelSize: completeProfileBody.fontSize
189 font.bold: completeProfileBody.fontBold394 font.bold: completeProfileBody.fontBold
190 wrapMode: Text.NoWrap395 wrapMode: Text.WordWrap
396 color: hifi.colors.white
397 linkColor: hifi.colors.blueAccent
191 lineHeight: 1398 lineHeight: 1
192 lineHeightMode: Text.ProportionalHeight399 lineHeightMode: Text.ProportionalHeight
193 horizontalAlignment: Text.AlignHCenter
194 linkColor: hifi.colors.blueAccent
195 400
196 onLinkActivated: {401 onLinkActivated: loginDialog.openUrl(link);
197 loginDialog.isLogIn = true;402
198 bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "errorString": "", "withSteam": true, "linkSteam": true });
199 }
200 Component.onCompleted: {403 Component.onCompleted: {
201 if (additionalTextMetrics.width > root.bannerWidth && root.isTablet) {404 if (termsTextMetrics.width > root.bannerWidth) {
202 additionalText.width = root.bannerWidth;405 termsText.width = root.bannerWidth;
203 additionalText.wrapMode = Text.WordWrap;406 termsText.wrapMode = Text.WordWrap;
204 additionalText.verticalAlignment = Text.AlignLeft;407 additionalText.verticalAlignment = Text.AlignLeft;
205 additionalText.horizontalAlignment = Text.AlignLeft;408 additionalText.horizontalAlignment = Text.AlignLeft;
206 additionalTextContainer.height = (additionalTextMetrics.width / root.bannerWidth) * additionalTextMetrics.height;409 termsContainer.height = (termsTextMetrics.width / root.bannerWidth) * termsTextMetrics.height;
207 additionalTextContainer.anchors.left = buttons.left;410 termsContainer.anchors.left = buttons.left;
208 } else {411 } else {
209 additionalText.anchors.centerIn = additionalTextContainer;412 termsText.anchors.centerIn = termsContainer;
210 }413 }
211 }414 }
212 }415 }
213 }416 }
214 417
215 Item {418 Item {
216 id: termsContainer419 id: additionalTextContainer
217 width: parent.width420 width: parent.width
218 height: termsTextMetrics.height421 height: additionalTextMetrics.height
219 anchors {422 anchors {
220 top: additionalTextContainer.bottom423 top: termsContainer.bottom
221 horizontalCenter: parent.horizontalCenter424 horizontalCenter: parent.horizontalCenter
222 topMargin: 2 * hifi.dimensions.contentSpacing.y425 topMargin: 2 * hifi.dimensions.contentSpacing.y
223 left: parent.left426 left: parent.left
224 }427 }
428
225 TextMetrics {429 TextMetrics {
226 id: termsTextMetrics430 id: additionalTextMetrics
227 font: termsText.font431 font: additionalText.font
228 text: completeProfileBody.termsContainerText432 text: "Already have a High Fidelity profile? Link to an existing profile here."
229 Component.onCompleted: {
230 // with the link.
231 termsText.text = qsTr("By creating this user profile, you agree to <a href='https://highfidelity.com/terms'>High Fidelity's Terms of Service</a>")
232 }
233 }433 }
234 434
235 HifiStylesUit.InfoItem {435 HifiStylesUit.ShortcutText {
236 id: termsText436 id: additionalText
237 text: completeProfileBody.termsContainerText437 text: "<a href='https://fake.link'>Already have a High Fidelity profile? Link to an existing profile here.</a>"
438 width: root.bannerWidth;
238 font.family: completeProfileBody.fontFamily439 font.family: completeProfileBody.fontFamily
239 font.pixelSize: completeProfileBody.fontSize440 font.pixelSize: completeProfileBody.fontSize
240 font.bold: completeProfileBody.fontBold441 font.bold: completeProfileBody.fontBold
241 wrapMode: Text.WordWrap442 wrapMode: Text.NoWrap
242 color: hifi.colors.lightGray
243 linkColor: hifi.colors.blueAccent
244 lineHeight: 1443 lineHeight: 1
245 lineHeightMode: Text.ProportionalHeight444 lineHeightMode: Text.ProportionalHeight
445 horizontalAlignment: Text.AlignHCenter
446 linkColor: hifi.colors.blueAccent
246 447
247 onLinkActivated: loginDialog.openUrl(link);448 onLinkActivated: {
248 449 bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "errorString": "",
450 "withSteam": completeProfileBody.withSteam, "linkSteam": completeProfileBody.withSteam, "withOculus": completeProfileBody.withOculus,
451 "linkOculus": completeProfileBody.withOculus });
452 }
249 Component.onCompleted: {453 Component.onCompleted: {
250 if (termsTextMetrics.width > root.bannerWidth && root.isTablet) {454 if (additionalTextMetrics.width > root.bannerWidth) {
251 termsText.width = root.bannerWidth;455 additionalText.wrapMode = Text.WordWrap;
252 termsText.wrapMode = Text.WordWrap;
253 additionalText.verticalAlignment = Text.AlignLeft;456 additionalText.verticalAlignment = Text.AlignLeft;
254 additionalText.horizontalAlignment = Text.AlignLeft;457 additionalText.horizontalAlignment = Text.AlignLeft;
255 termsContainer.height = (termsTextMetrics.width / root.bannerWidth) * termsTextMetrics.height;458 additionalTextContainer.height = (additionalTextMetrics.width / root.bannerWidth) * additionalTextMetrics.height;
256 termsContainer.anchors.left = buttons.left;459 additionalTextContainer.anchors.left = buttons.left;
257 } else {460 } else {
258 termsText.anchors.centerIn = termsContainer;461 additionalText.anchors.centerIn = additionalTextContainer;
259 }462 }
260 }463 }
261 }464 }
262 }465 }
263 }466 }
467 function recalculateErrorMessage() {
468 if (completeProfileBody.errorString !== "") {
469 loginErrorMessage.visible = true;
470 var errorLength = completeProfileBody.errorString.split(/\r\n|\r|\n/).length;
471 var errorStringEdited = completeProfileBody.errorString.replace(/[\n\r]+/g, "\n");
472 loginErrorMessage.text = errorStringEdited;
473 if (errorLength > 1.0) {
474 loginErrorMessage.wrapMode = Text.WordWrap;
475 loginErrorMessage.verticalAlignment = Text.AlignLeft;
476 loginErrorMessage.horizontalAlignment = Text.AlignLeft;
477 errorContainer.height = errorLength * loginErrorMessageTextMetrics.height;
478 } else if (loginErrorMessageTextMetrics.width > root.bannerWidth) {
479 loginErrorMessage.wrapMode = Text.WordWrap;
480 loginErrorMessage.verticalAlignment = Text.AlignLeft;
481 loginErrorMessage.horizontalAlignment = Text.AlignLeft;
482 errorContainer.height = (loginErrorMessageTextMetrics.width / root.bannerWidth) * loginErrorMessageTextMetrics.height;
483 } else {
484 loginErrorMessage.wrapMode = Text.NoWrap;
485 loginErrorMessage.verticalAlignment = Text.AlignVCenter;
486 loginErrorMessage.horizontalAlignment = Text.AlignHCenter;
487 errorContainer.height = loginErrorMessageTextMetrics.height;
488 }
489 }
490 }
264 }491 }
265 492
266 Connections {493 Connections {
267 target: loginDialog494 target: loginDialog
268 onHandleCreateCompleted: {495 onHandleCreateCompleted: {
269 console.log("Create Succeeded")496 console.log("Create Succeeded");
270
271 if (completeProfileBody.withSteam) {497 if (completeProfileBody.withSteam) {
272 if (completeProfileBody.loginDialogPoppedUp) {498 if (completeProfileBody.loginDialogPoppedUp) {
273 var data = {499 var data = {
@@ -277,20 +503,24 @@ Item { · 3 unmodified lines
277 }503 }
278 loginDialog.loginThroughSteam();504 loginDialog.loginThroughSteam();
279 }505 }
280 bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": completeProfileBody.withSteam, "linkSteam": false });506 bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": completeProfileBody.withSteam, "linkSteam": false,
507 "withOculus": completeProfileBody.withOculus, "linkOculus": false });
281 }508 }
282 onHandleCreateFailed: {509 onHandleCreateFailed: {
283 console.log("Create Failed: " + error);510 console.log("Create Failed: " + error);
284 if (completeProfileBody.withSteam) {511 if (completeProfileBody.withSteam || completeProfileBody.withOculus) {
285 if (completeProfileBody.loginDialogPoppedUp) {512 if (completeProfileBody.loginDialogPoppedUp) {
513 action = completeProfileBody.withSteam ? "Steam" : "Oculus";
286 var data = {514 var data = {
287 "action": "user failed to create a profile with Steam from the complete profile screen"515 "action": "user failed to create a profile with " + action + " from the complete profile screen"
288 }516 }
289 UserActivityLogger.logAction("encourageLoginDialog", data);517 UserActivityLogger.logAction("encourageLoginDialog", data);
290 }518 }
291 }519 }
292 520 if (!completeProfileBody.withOculus) {
293 bodyLoader.setSource("UsernameCollisionBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": completeProfileBody.withSteam });521 bodyLoader.setSource("UsernameCollisionBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": completeProfileBody.withSteam,
522 "withOculus": completeProfileBody.withOculus });
523 }
294 }524 }
295 }525 }
296 526
@@ -302,5 +532,6 @@ Item { · 5 unmodified lines
302 }532 }
303 d.resize();533 d.resize();
304 root.text = "";534 root.text = "";
535 usernameField.forceActiveFocus();
305 }536 }
306}537}
interface/resources/qml/LoginDialog/LinkAccountBody.qml+30−57
@@ -36,9 +36,10 @@ Item { · 35 unmodified lines
36 property bool keyboardRaised: false36 property bool keyboardRaised: false
37 property bool punctuationMode: false37 property bool punctuationMode: false
38 38
39 property bool withSteam: false39 property bool withSteam: withSteam
40 property bool linkSteam: linkSteam40 property bool linkSteam: linkSteam
41 property bool withOculus: false41 property bool withOculus: withOculus
42 property bool linkOculus: linkOculus
42 property string errorString: errorString43 property string errorString: errorString
43 property bool lostFocus: false44 property bool lostFocus: false
44 45
@@ -83,23 +84,24 @@ Item { · 38 unmodified lines
83 }84 }
84 UserActivityLogger.logAction("encourageLoginDialog", data);85 UserActivityLogger.logAction("encourageLoginDialog", data);
85 }86 }
86 87 bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": linkAccountBody.withSteam,
87 bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": linkAccountBody.withSteam, "withOculus": linkAccountBody.withOculus, "linkSteam": linkAccountBody.linkSteam });88 "withOculus": linkAccountBody.withOculus, "linkSteam": linkAccountBody.linkSteam, "linkOculus": linkAccountBody.linkOculus });
88 }89 }
89 90
90 function init() {91 function init() {
91 // going to/from sign in/up dialog.92 // going to/from sign in/up dialog.
92 loginDialog.isLogIn = true;
93 loginErrorMessage.text = linkAccountBody.errorString;93 loginErrorMessage.text = linkAccountBody.errorString;
94 loginErrorMessage.visible = (linkAccountBody.errorString !== "");94 loginErrorMessage.visible = (linkAccountBody.errorString !== "");
95 loginButton.text = !linkAccountBody.linkSteam ? "Log In" : "Link Account";95 if (loginErrorMessageTextMetrics.width > emailField.width) {
96 loginErrorMessage.wrapMode = Text.WordWrap;
97 errorContainer.height = (loginErrorMessageTextMetrics.width / emailField.width) * loginErrorMessageTextMetrics.height;
98 }
99 loginButton.text = (!linkAccountBody.linkSteam && !linkAccountBody.linkOculus) ? "Log In" : "Link Account";
96 loginButton.color = hifi.buttons.blue;100 loginButton.color = hifi.buttons.blue;
97 emailField.placeholderText = "Username or Email";101 emailField.placeholderText = "Username or Email";
98 var savedUsername = Settings.getValue("keepMeLoggedIn/savedUsername", "");102 var savedUsername = Settings.getValue("keepMeLoggedIn/savedUsername", "");
99 emailField.text = keepMeLoggedInCheckbox.checked ? savedUsername === "Unknown user" ? "" : savedUsername : "";103 emailField.text = keepMeLoggedInCheckbox.checked ? savedUsername === "Unknown user" ? "" : savedUsername : "";
100 if (linkAccountBody.linkSteam) {104 if (linkAccountBody.linkSteam || linkAccountBody.linkOculus) {
101 steamInfoText.anchors.top = passwordField.bottom;
102 keepMeLoggedInCheckbox.anchors.top = steamInfoText.bottom;
103 loginButton.width = (passwordField.width - hifi.dimensions.contentSpacing.x) / 2;105 loginButton.width = (passwordField.width - hifi.dimensions.contentSpacing.x) / 2;
104 loginButton.anchors.right = emailField.right;106 loginButton.anchors.right = emailField.right;
105 } else {107 } else {
@@ -125,7 +127,7 @@ Item { · 19 unmodified lines
125 id: loginContainer127 id: loginContainer
126 width: emailField.width128 width: emailField.width
127 height: errorContainer.height + emailField.height + passwordField.height + 5.5 * hifi.dimensions.contentSpacing.y +129 height: errorContainer.height + emailField.height + passwordField.height + 5.5 * hifi.dimensions.contentSpacing.y +
128 keepMeLoggedInCheckbox.height + loginButton.height + cantAccessTextMetrics.height + continueButton.height + steamInfoTextMetrics.height130 keepMeLoggedInCheckbox.height + loginButton.height + cantAccessTextMetrics.height + continueButton.height
129 anchors {131 anchors {
130 top: parent.top132 top: parent.top
131 topMargin: root.bannerHeight + 0.25 * parent.height133 topMargin: root.bannerHeight + 0.25 * parent.height
@@ -135,7 +137,7 @@ Item { · 3 unmodified lines
135 137
136 Item {138 Item {
137 id: errorContainer139 id: errorContainer
138 width: loginErrorMessageTextMetrics.width140 width: parent.width
139 height: loginErrorMessageTextMetrics.height141 height: loginErrorMessageTextMetrics.height
140 anchors {142 anchors {
141 bottom: emailField.top;143 bottom: emailField.top;
@@ -304,7 +306,7 @@ Item { · 162 unmodified lines
304 fontSize: linkAccountBody.fontSize306 fontSize: linkAccountBody.fontSize
305 fontBold: linkAccountBody.fontBold307 fontBold: linkAccountBody.fontBold
306 color: hifi.buttons.noneBorderlessWhite;308 color: hifi.buttons.noneBorderlessWhite;
307 visible: linkAccountBody.linkSteam309 visible: linkAccountBody.linkSteam || linkAccountBody.linkOculus
308 anchors {310 anchors {
309 top: keepMeLoggedInCheckbox.bottom311 top: keepMeLoggedInCheckbox.bottom
310 topMargin: hifi.dimensions.contentSpacing.y312 topMargin: hifi.dimensions.contentSpacing.y
@@ -315,10 +317,9 @@ Item { · 4 unmodified lines
315 "action": "user clicked cancel at link account screen"317 "action": "user clicked cancel at link account screen"
316 };318 };
317 UserActivityLogger.logAction("encourageLoginDialog", data);319 UserActivityLogger.logAction("encourageLoginDialog", data);
318 loginDialog.dismissLoginDialog();
319 }320 }
320 321 bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": linkAccountBody.withSteam,
321 bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": linkAccountBody.withSteam, "errorString": "" });322 "withOculus": linkAccountBody.withOculus, "errorString": "" });
322 }323 }
323 }324 }
324 HifiControlsUit.Button {325 HifiControlsUit.Button {
@@ -337,33 +338,6 @@ Item { · 12 unmodified lines
337 linkAccountBody.login();338 linkAccountBody.login();
338 }339 }
339 }340 }
340 TextMetrics {
341 id: steamInfoTextMetrics
342 font: steamInfoText.font
343 text: steamInfoText.text
344 }
345 Text {
346 id: steamInfoText
347 width: root.bannerWidth
348 visible: linkAccountBody.linkSteam
349 anchors {
350 top: loginButton.bottom
351 topMargin: hifi.dimensions.contentSpacing.y
352 left: emailField.left
353 }
354
355 font.family: linkAccountBody.fontFamily
356 font.pixelSize: linkAccountBody.textFieldFontSize
357 color: "white"
358 text: qsTr("Your Steam account information will not be exposed to others.");
359 verticalAlignment: Text.AlignVCenter
360 horizontalAlignment: Text.AlignHCenter
361 Component.onCompleted: {
362 if (steamInfoTextMetrics.width > root.bannerWidth) {
363 steamInfoText.wrapMode = Text.WordWrap;
364 }
365 }
366 }
367 TextMetrics {341 TextMetrics {
368 id: cantAccessTextMetrics342 id: cantAccessTextMetrics
369 font: cantAccessText.font343 font: cantAccessText.font
@@ -372,7 +346,7 @@ Item { · 2 unmodified lines
372 HifiStylesUit.ShortcutText {346 HifiStylesUit.ShortcutText {
373 id: cantAccessText347 id: cantAccessText
374 z: 10348 z: 10
375 visible: !linkAccountBody.linkSteam349 visible: !linkAccountBody.linkSteam && !linkAccountBody.linkOculus
376 anchors {350 anchors {
377 top: loginButton.bottom351 top: loginButton.bottom
378 topMargin: hifi.dimensions.contentSpacing.y352 topMargin: hifi.dimensions.contentSpacing.y
@@ -423,10 +397,10 @@ Item { · 44 unmodified lines
423 buttonGlyphSize: 24397 buttonGlyphSize: 24
424 buttonGlyphRightMargin: 10398 buttonGlyphRightMargin: 10
425 onClicked: {399 onClicked: {
426 // if (loginDialog.isOculusStoreRunning()) {400 if (loginDialog.isOculusRunning()) {
427 // linkAccountBody.withOculus = true;401 linkAccountBody.withOculus = true;
428 // loginDialog.loginThroughSteam();402 loginDialog.loginThroughOculus();
429 // } else403 } else
430 if (loginDialog.isSteamRunning()) {404 if (loginDialog.isSteamRunning()) {
431 linkAccountBody.withSteam = true;405 linkAccountBody.withSteam = true;
432 loginDialog.loginThroughSteam();406 loginDialog.loginThroughSteam();
@@ -446,18 +420,17 @@ Item { · 13 unmodified lines
446 }420 }
447 421
448 bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader,422 bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader,
449 "withSteam": linkAccountBody.withSteam, "withOculus": linkAccountBody.withOculus, "linkSteam": linkAccountBody.linkSteam });423 "withSteam": linkAccountBody.withSteam, "withOculus": linkAccountBody.withOculus, "linkSteam": linkAccountBody.linkSteam, "linkOculus": linkAccountBody.linkOculus });
450 }424 }
451 Component.onCompleted: {425 Component.onCompleted: {
452 if (linkAccountBody.linkSteam) {426 if (linkAccountBody.linkSteam || linkAccountBody.linkOculus) {
453 continueButton.visible = false;427 continueButton.visible = false;
454 return;428 return;
455 }429 }
456 // if (loginDialog.isOculusStoreRunning()) {430 if (loginDialog.isOculusRunning()) {
457 // continueButton.text = qsTr("CONTINUE WITH OCULUS");431 continueButton.text = qsTr("CONTINUE WITH OCULUS");
458 // continueButton.buttonGlyph = hifi.glyphs.oculus;432 continueButton.buttonGlyph = hifi.glyphs.oculus;
459 // } else433 } else if (loginDialog.isSteamRunning()) {
460 if (loginDialog.isSteamRunning()) {
461 continueButton.text = qsTr("CONTINUE WITH STEAM");434 continueButton.text = qsTr("CONTINUE WITH STEAM");
462 continueButton.buttonGlyph = hifi.glyphs.steamSquare;435 continueButton.buttonGlyph = hifi.glyphs.steamSquare;
463 } else {436 } else {
@@ -470,7 +443,7 @@ Item { · 6 unmodified lines
470 id: signUpContainer443 id: signUpContainer
471 width: loginContainer.width444 width: loginContainer.width
472 height: signUpTextMetrics.height445 height: signUpTextMetrics.height
473 visible: !linkAccountBody.linkSteam446 visible: !linkAccountBody.linkSteam && !linkAccountBody.linkOculus
474 anchors {447 anchors {
475 left: loginContainer.left448 left: loginContainer.left
476 top: loginContainer.bottom449 top: loginContainer.bottom
@@ -519,7 +492,7 @@ Item { · 42 unmodified lines
519 UserActivityLogger.logAction("encourageLoginDialog", data);492 UserActivityLogger.logAction("encourageLoginDialog", data);
520 }493 }
521 bodyLoader.setSource("SignUpBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader,494 bodyLoader.setSource("SignUpBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader,
522 "errorString": "", "linkSteam": linkAccountBody.linkSteam });495 "errorString": "" });
523 }496 }
524 }497 }
525 }498 }
@@ -543,7 +516,7 @@ Item { · 17 unmodified lines
543 fontFamily: linkAccountBody.fontFamily516 fontFamily: linkAccountBody.fontFamily
544 fontSize: linkAccountBody.fontSize517 fontSize: linkAccountBody.fontSize
545 fontBold: linkAccountBody.fontBold518 fontBold: linkAccountBody.fontBold
546 visible: linkAccountBody.loginDialogPoppedUp && !linkAccountBody.linkSteam;519 visible: loginDialog.getLoginDialogPoppedUp() && !linkAccountBody.linkSteam && !linkAccountBody.linkOculus;
547 onClicked: {520 onClicked: {
548 if (linkAccountBody.loginDialogPoppedUp) {521 if (linkAccountBody.loginDialogPoppedUp) {
549 var data = {522 var data = {
interface/resources/qml/LoginDialog/LoggingInBody.qml+114−18
@@ -29,6 +29,8 @@ Item { · 28 unmodified lines
29 property bool withSteam: withSteam29 property bool withSteam: withSteam
30 property bool withOculus: withOculus30 property bool withOculus: withOculus
31 property bool linkSteam: linkSteam31 property bool linkSteam: linkSteam
32 property bool linkOculus: linkOculus
33 property bool createOculus: createOculus
32 34
33 readonly property bool loginDialogPoppedUp: loginDialog.getLoginDialogPoppedUp()35 readonly property bool loginDialogPoppedUp: loginDialog.getLoginDialogPoppedUp()
34 36
@@ -75,15 +77,25 @@ Item { · 40 unmodified lines
75 }77 }
76 }78 }
77 79
80 Timer {
81 id: oculusSuccessTimer
82 interval: 500;
83 running: false;
84 repeat: false;
85 onTriggered: {
86 loginDialog.loginThroughOculus();
87 init();
88 }
89 }
90
78 function init() {91 function init() {
79 // For the process of logging in.92 // For the process of logging in.
80 loggingInText.wrapMode = Text.NoWrap;93 loggingInText.wrapMode = Text.NoWrap;
81 94 if (loggingInBody.createOculus) {
82 if (loggingInBody.linkSteam) {95 loggingInGlyph.text = hifi.glyphs.oculus;
83 loggingInGlyph.visible = true;96 loggingInGlyph.visible = true;
84 loggingInText.text = "Linking to Steam";97 loggingInText.text = "Creating account with Oculus";
85 loggingInText.x = loggingInHeader.width/2 - loggingInTextMetrics.width/2 + loggingInGlyphTextMetrics.width/2;98 loggingInText.x = loggingInHeader.width/2 - loggingInTextMetrics.width/2 + loggingInGlyphTextMetrics.width/2;
86 loginDialog.linkSteam();
87 } else if (loggingInBody.withSteam) {99 } else if (loggingInBody.withSteam) {
88 loggingInGlyph.visible = true;100 loggingInGlyph.visible = true;
89 loggingInText.text = "Logging in to Steam";101 loggingInText.text = "Logging in to Steam";
@@ -100,12 +112,18 @@ Item { · 10 unmodified lines
100 loggingInSpinner.visible = true;112 loggingInSpinner.visible = true;
101 }113 }
102 function loadingSuccess() {114 function loadingSuccess() {
103 loggingInSpinner.visible = false;
104 if (loggingInBody.linkSteam) {115 if (loggingInBody.linkSteam) {
105 loggingInText.text = "Linking to Steam";116 loggingInText.text = "Linking to Steam";
117 loggingInText.x = loggingInHeader.width/2 - loggingInTextMetrics.width/2 + loggingInGlyphTextMetrics.width/2;
106 loginDialog.linkSteam();118 loginDialog.linkSteam();
107 return;119 return;
120 } else if (loggingInBody.linkOculus) {
121 loggingInText.text = "Linking to Oculus";
122 loggingInText.x = loggingInHeader.width/2 - loggingInTextMetrics.width/2 + loggingInGlyphTextMetrics.width/2;
123 loginDialog.linkOculus();
124 return;
108 }125 }
126 loggingInSpinner.visible = false;
109 if (loggingInBody.withSteam) {127 if (loggingInBody.withSteam) {
110 // reset the flag.128 // reset the flag.
111 loggingInGlyph.visible = false;129 loggingInGlyph.visible = false;
@@ -246,6 +264,26 @@ Item { · 134 unmodified lines
246 verticalAlignment: Text.AlignVCenter;264 verticalAlignment: Text.AlignVCenter;
247 visible: false;265 visible: false;
248 }266 }
267 HifiControlsUit.Button {
268 id: okButton;
269 width: d.minWidthButton
270 height: d.minHeightButton
271 text: qsTr("OK")
272 color: hifi.buttons.white
273 anchors {
274 top: loggedInGlyph.bottom
275 topMargin: 3 * hifi.dimensions.contentSpacing.y
276 left: parent.left
277 leftMargin: (parent.width - width) / 2;
278 }
279 onClicked: {
280 root.tryDestroy();
281 if (loginDialog.getLoginDialogPoppedUp()) {
282 loginDialog.dismissLoginDialog();
283 }
284 }
285 visible: false
286 }
249 }287 }
250 }288 }
251 }289 }
@@ -257,6 +295,34 @@ Item { · 5 unmodified lines
257 295
258 Connections {296 Connections {
259 target: loginDialog297 target: loginDialog
298 onHandleCreateCompleted: {
299 console.log("Create Succeeded")
300 if (loggingInBody.withOculus) {
301 if (loggingInBody.loginDialogPoppedUp) {
302 var data = {
303 "action": "user created Oculus account successfully"
304 };
305 UserActivityLogger.logAction("encourageLoginDialog", data);
306 }
307 loggingInBody.createOculus = false;
308 loggingInText.text = "Account created!";
309 loggingInText.x = loggingInHeader.width/2 - loggingInTextMetrics.width/2 + loggingInGlyphTextMetrics.width/2;
310 oculusSuccessTimer.start();
311 }
312 }
313 onHandleCreateFailed: {
314 console.log("Create Failed: " + error);
315 if (loggingInBody.withOculus) {
316 if (loggingInBody.loginDialogPoppedUp) {
317 var data = {
318 "action": "user created Oculus account unsuccessfully"
319 };
320 UserActivityLogger.logAction("encourageLoginDialog", data);
321 }
322 bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": loggingInBody.withSteam,
323 "withOculus": loggingInBody.withOculus, "errorString": error });
324 }
325 }
260 onHandleLinkCompleted: {326 onHandleLinkCompleted: {
261 console.log("Link Succeeded");327 console.log("Link Succeeded");
262 if (loggingInBody.linkSteam) {328 if (loggingInBody.linkSteam) {
@@ -267,21 +333,40 @@ Item { · 4 unmodified lines
267 };333 };
268 UserActivityLogger.logAction("encourageLoginDialog", data);334 UserActivityLogger.logAction("encourageLoginDialog", data);
269 }335 }
270 336 } else if (loggingInBody.linkOculus) {
271 loggingInBody.loadingSuccess();337 loggingInBody.linkOculus = false;
338 if (loggingInBody.loginDialogPoppedUp) {
339 var data = {
340 "action": "user linked Oculus with their hifi account credentials successfully"
341 };
342 UserActivityLogger.logAction("encourageLoginDialog", data);
343 }
272 }344 }
345 loggingInBody.loadingSuccess();
273 }346 }
274 onHandleLinkFailed: {347 onHandleLinkFailed: {
275 console.log("Link Failed: " + error);348 console.log("Link Failed: " + error);
276 if (loggingInBody.linkSteam) {349 loggingInSpinner.visible = false;
350 if (loggingInBody.linkOculus) {
351 loggingInText.text = "Oculus failed to link";
352 if (loggingInBody.loginDialogPoppedUp) {
353 var data = {
354 "action": "user linked Oculus unsuccessfully"
355 };
356 UserActivityLogger.logAction("encourageLoginDialog", data);
357 }
358 okButton.visible = true;
359 } else if (loggingInBody.linkSteam){
277 if (loggingInBody.loginDialogPoppedUp) {360 if (loggingInBody.loginDialogPoppedUp) {
278 var data = {361 var data = {
279 "action": "user linked Steam unsuccessfully"362 "action": "user linked Steam unsuccessfully"
280 };363 };
281 UserActivityLogger.logAction("encourageLoginDialog", data);364 UserActivityLogger.logAction("encourageLoginDialog", data);
282 }365 }
366 } else {
367 bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": loggingInBody.linkSteam,
368 "linkOculus": loggingInBody.linkOculus, "errorString": error });
283 }369 }
284 bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": true, "errorString": error });
285 }370 }
286 371
287 onHandleLoginCompleted: {372 onHandleLoginCompleted: {
@@ -292,8 +377,19 @@ Item { · 4 unmodified lines
292 onHandleLoginFailed: {377 onHandleLoginFailed: {
293 console.log("Login Failed")378 console.log("Login Failed")
294 loggingInSpinner.visible = false;379 loggingInSpinner.visible = false;
380 loggingInGlyph.visible = false;
295 var errorString = "";381 var errorString = "";
296 if (loggingInBody.linkSteam && loggingInBody.withSteam) {382 if (loggingInBody.linkOculus && loggingInBody.withOculus) {
383 errorString = "Username or password is incorrect.";
384 if (loggingInBody.loginDialogPoppedUp) {
385 var data = {
386 "action": "user failed to link Oculus with their hifi account credentials"
387 };
388 UserActivityLogger.logAction("encourageLoginDialog", data);
389 }
390 bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": loggingInBody.withSteam,
391 "withOculus": loggingInBody.withOculus, "linkSteam": loggingInBody.linkSteam, "linkOculus": loggingInBody.linkOculus, "errorString": errorString });
392 } else if (loggingInBody.linkSteam && loggingInBody.withSteam) {
297 errorString = "Username or password is incorrect.";393 errorString = "Username or password is incorrect.";
298 if (loggingInBody.loginDialogPoppedUp) {394 if (loggingInBody.loginDialogPoppedUp) {
299 var data = {395 var data = {
@@ -301,9 +397,9 @@ Item { · 1 unmodified line
301 };397 };
302 UserActivityLogger.logAction("encourageLoginDialog", data);398 UserActivityLogger.logAction("encourageLoginDialog", data);
303 }399 }
304 bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": loggingInBody.withSteam, "linkSteam": loggingInBody.linkSteam, "errorString": errorString });400 bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": loggingInBody.withSteam,
401 "withOculus": loggingInBody.withOculus, "linkSteam": loggingInBody.linkSteam, "linkOculus": loggingInBody.linkOculus, "errorString": errorString });
305 } else if (loggingInBody.withSteam) {402 } else if (loggingInBody.withSteam) {
306 loggingInGlyph.visible = false;
307 errorString = "Your Steam authentication has failed. Please make sure you are logged into Steam and try again.";403 errorString = "Your Steam authentication has failed. Please make sure you are logged into Steam and try again.";
308 if (loggingInBody.loginDialogPoppedUp) {404 if (loggingInBody.loginDialogPoppedUp) {
309 var data = {405 var data = {
@@ -311,19 +407,19 @@ Item { · 1 unmodified line
311 };407 };
312 UserActivityLogger.logAction("encourageLoginDialog", data);408 UserActivityLogger.logAction("encourageLoginDialog", data);
313 }409 }
314 bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": loggingInBody.withSteam, "errorString": errorString });410 bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": loggingInBody.withSteam,
411 "withOculus": loggingInBody.withOculus, "linkSteam": loggingInBody.linkSteam, "linkOculus": loggingInBody.linkOculus, "errorString": errorString });
315 } else if (loggingInBody.withOculus) {412 } else if (loggingInBody.withOculus) {
316 loggingInGlyph.visible = false;413 errorString = "Your Oculus account is not connected to an existing High Fidelity account. Please create a new one."
317 errorString = "Your Oculus authentication has failed. Please make sure you are logged into Oculus and try again."
318 if (loggingInBody.loginDialogPoppedUp) {414 if (loggingInBody.loginDialogPoppedUp) {
319 var data = {415 var data = {
320 "action": "user failed to authenticate with Oculus to log in"416 "action": "user failed to authenticate with Oculus to log in"
321 };417 };
322 UserActivityLogger.logAction("encourageLoginDialog", data);418 UserActivityLogger.logAction("encourageLoginDialog", data);
323 }419 }
324 bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "errorString": errorString });420 bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": loggingInBody.withSteam,
325 }421 "withOculus": loggingInBody.withOculus, "linkSteam": loggingInBody.linkSteam, "linkOculus": loggingInBody.linkOculus, "errorString": errorString });
326 else {422 } else {
327 errorString = "Username or password is incorrect.";423 errorString = "Username or password is incorrect.";
328 if (loggingInBody.loginDialogPoppedUp) {424 if (loggingInBody.loginDialogPoppedUp) {
329 var data = {425 var data = {
interface/resources/qml/LoginDialog/SignUpBody.qml+54−6
@@ -23,6 +23,7 @@ Item { · 22 unmodified lines
23 clip: true23 clip: true
24 height: root.height24 height: root.height
25 width: root.width25 width: root.width
26 readonly property string termsContainerText: qsTr("By signing up, you agree to High Fidelity's Terms of Service")
26 property int textFieldHeight: 3127 property int textFieldHeight: 31
27 property string fontFamily: "Raleway"28 property string fontFamily: "Raleway"
28 property int fontSize: 1529 property int fontSize: 15
@@ -37,7 +38,6 @@ Item { · 8 unmodified lines
37 onKeyboardRaisedChanged: d.resize();38 onKeyboardRaisedChanged: d.resize();
38 39
39 property string errorString: errorString40 property string errorString: errorString
40 property bool linkSteam: linkSteam
41 property bool lostFocus: false41 property bool lostFocus: false
42 42
43 readonly property bool loginDialogPoppedUp: loginDialog.getLoginDialogPoppedUp()43 readonly property bool loginDialogPoppedUp: loginDialog.getLoginDialogPoppedUp()
@@ -73,7 +73,6 @@ Item { · 29 unmodified lines
73 73
74 function init() {74 function init() {
75 // going to/from sign in/up dialog.75 // going to/from sign in/up dialog.
76 loginDialog.isLogIn = false;
77 emailField.placeholderText = "Email";76 emailField.placeholderText = "Email";
78 emailField.text = "";77 emailField.text = "";
79 emailField.anchors.top = usernameField.bottom;78 emailField.anchors.top = usernameField.bottom;
@@ -353,7 +352,7 @@ Item { · 273 unmodified lines
353 }352 }
354 UserActivityLogger.logAction("encourageLoginDialog", data);353 UserActivityLogger.logAction("encourageLoginDialog", data);
355 }354 }
356 bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": signUpBody.linkSteam });355 bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": false });
357 }356 }
358 }357 }
359 HifiControlsUit.Button {358 HifiControlsUit.Button {
@@ -380,6 +379,54 @@ Item { · 20 unmodified lines
380 signUpBody.signup();379 signUpBody.signup();
381 }380 }
382 }381 }
382 Item {
383 id: termsContainer
384 width: parent.width
385 height: termsTextMetrics.height
386 anchors {
387 top: signUpButton.bottom
388 horizontalCenter: parent.horizontalCenter
389 topMargin: 2 * hifi.dimensions.contentSpacing.y
390 left: parent.left
391 }
392 TextMetrics {
393 id: termsTextMetrics
394 font: termsText.font
395 text: signUpBody.termsContainerText
396 Component.onCompleted: {
397 // with the link.
398 termsText.text = qsTr("By signing up, you agree to <a href='https://highfidelity.com/terms'>High Fidelity's Terms of Service</a>")
399 }
400 }
401
402 HifiStylesUit.InfoItem {
403 id: termsText
404 text: signUpBody.termsContainerText
405 font.family: signUpBody.fontFamily
406 font.pixelSize: signUpBody.fontSize
407 font.bold: signUpBody.fontBold
408 wrapMode: Text.WordWrap
409 color: hifi.colors.white
410 linkColor: hifi.colors.blueAccent
411 lineHeight: 1
412 lineHeightMode: Text.ProportionalHeight
413
414 onLinkActivated: loginDialog.openUrl(link);
415
416 Component.onCompleted: {
417 if (termsTextMetrics.width > root.bannerWidth) {
418 termsText.width = root.bannerWidth;
419 termsText.wrapMode = Text.WordWrap;
420 additionalText.verticalAlignment = Text.AlignLeft;
421 additionalText.horizontalAlignment = Text.AlignLeft;
422 termsContainer.height = (termsTextMetrics.width / root.bannerWidth) * termsTextMetrics.height;
423 termsContainer.anchors.left = buttons.left;
424 } else {
425 termsText.anchors.centerIn = termsContainer;
426 }
427 }
428 }
429 }
383 }430 }
384 }431 }
385 432
@@ -433,14 +480,15 @@ Item { · 47 unmodified lines
433 480
434 if (errorString !== "") {481 if (errorString !== "") {
435 loginErrorMessage.visible = true;482 loginErrorMessage.visible = true;
483 var errorLength = errorString.split(/\r\n|\r|\n/).length;
436 var errorStringEdited = errorString.replace(/[\n\r]+/g, "\n");484 var errorStringEdited = errorString.replace(/[\n\r]+/g, "\n");
437 loginErrorMessage.text = errorStringEdited;485 loginErrorMessage.text = errorStringEdited;
438 loginErrorMessageTextMetrics.text = errorString;486 if (errorLength > 1.0) {
439 if (loginErrorMessageTextMetrics.width > usernameField.width) {487 loginErrorMessage.width = root.bannerWidth;
440 loginErrorMessage.wrapMode = Text.WordWrap;488 loginErrorMessage.wrapMode = Text.WordWrap;
441 loginErrorMessage.verticalAlignment = Text.AlignLeft;489 loginErrorMessage.verticalAlignment = Text.AlignLeft;
442 loginErrorMessage.horizontalAlignment = Text.AlignLeft;490 loginErrorMessage.horizontalAlignment = Text.AlignLeft;
443 errorContainer.height = (loginErrorMessageTextMetrics.width / usernameField.width) * loginErrorMessageTextMetrics.height;491 errorContainer.height = errorLength * loginErrorMessageTextMetrics.height;
444 }492 }
445 errorContainer.anchors.bottom = usernameField.top;493 errorContainer.anchors.bottom = usernameField.top;
446 errorContainer.anchors.bottomMargin = hifi.dimensions.contentSpacing.y;494 errorContainer.anchors.bottomMargin = hifi.dimensions.contentSpacing.y;
interface/resources/qml/LoginDialog/UsernameCollisionBody.qml+78−8
@@ -19,6 +19,7 @@ import TabletScriptingInterface 1.0 · 18 unmodified lines
19Item {19Item {
20 id: usernameCollisionBody20 id: usernameCollisionBody
21 clip: true21 clip: true
22 readonly property string termsContainerText: qsTr("By creating this user profile, you agree to High Fidelity's Terms of Service")
22 width: root.width23 width: root.width
23 height: root.height24 height: root.height
24 readonly property string fontFamily: "Raleway"25 readonly property string fontFamily: "Raleway"
@@ -26,13 +27,18 @@ Item { · 1 unmodified line
26 readonly property int textFieldFontSize: 1827 readonly property int textFieldFontSize: 18
27 readonly property bool fontBold: true28 readonly property bool fontBold: true
28 29
29 readonly property bool withSteam: withSteam30 property bool withSteam: withSteam
31 property bool withOculus: withOculus
30 32
31 readonly property bool loginDialogPoppedUp: loginDialog.getLoginDialogPoppedUp()33 readonly property bool loginDialogPoppedUp: loginDialog.getLoginDialogPoppedUp()
32 34
33 function create() {35 function create() {
34 mainTextContainer.visible = false36 mainTextContainer.visible = false
35 loginDialog.createAccountFromSteam(textField.text);37 if (usernameCollisionBody.withOculus) {
38 loginDialog.createAccountFromOculus(textField.text);
39 } else if (usernameCollisionBody.withSteam) {
40 loginDialog.createAccountFromSteam(textField.text);
41 }
36 }42 }
37 43
38 property bool keyboardEnabled: false44 property bool keyboardEnabled: false
@@ -90,12 +96,19 @@ Item { · 51 unmodified lines
90 font.family: usernameCollisionBody.fontFamily96 font.family: usernameCollisionBody.fontFamily
91 font.pixelSize: usernameCollisionBody.fontSize97 font.pixelSize: usernameCollisionBody.fontSize
92 font.bold: usernameCollisionBody.fontBold98 font.bold: usernameCollisionBody.fontBold
93 text: qsTr("Your Steam username is not available.");99 text: qsTr("");
94 wrapMode: Text.WordWrap100 wrapMode: Text.WordWrap
95 color: hifi.colors.redAccent101 color: hifi.colors.redAccent
96 lineHeight: 1102 lineHeight: 1
97 lineHeightMode: Text.ProportionalHeight103 lineHeightMode: Text.ProportionalHeight
98 horizontalAlignment: Text.AlignHCenter104 horizontalAlignment: Text.AlignHCenter
105 Component.onCompleted: {
106 if (usernameCollisionBody.withOculus) {
107 text = qsTr("Your Oculus username is not available.");
108 } else if (usernameCollisionBody.withSteam) {
109 text = qsTr("Your Steam username is not available.");
110 }
111 }
99 }112 }
100 113
101 114
@@ -164,7 +177,8 @@ Item { · 62 unmodified lines
164 fontSize: usernameCollisionBody.fontSize177 fontSize: usernameCollisionBody.fontSize
165 fontBold: usernameCollisionBody.fontBold178 fontBold: usernameCollisionBody.fontBold
166 onClicked: {179 onClicked: {
167 bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "errorString": "" });180 bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": usernameCollisionBody.withSteam,
181 "withOculus": usernameCollisionBody.withOculus, "errorString": "" });
168 }182 }
169 }183 }
170 HifiControlsUit.Button {184 HifiControlsUit.Button {
@@ -187,6 +201,55 @@ Item { · 16 unmodified lines
187 }201 }
188 }202 }
189 }203 }
204 Item {
205 id: termsContainer
206 width: parent.width
207 height: termsTextMetrics.height
208 anchors {
209 top: buttons.bottom
210 horizontalCenter: parent.horizontalCenter
211 topMargin: 2 * hifi.dimensions.contentSpacing.y
212 left: parent.left
213 leftMargin: (parent.width - buttons.width) / 2
214 }
215 TextMetrics {
216 id: termsTextMetrics
217 font: termsText.font
218 text: usernameCollisionBody.termsContainerText
219 Component.onCompleted: {
220 // with the link.
221 termsText.text = qsTr("By creating this user profile, you agree to <a href='https://highfidelity.com/terms'>High Fidelity's Terms of Service</a>")
222 }
223 }
224
225 HifiStylesUit.InfoItem {
226 id: termsText
227 text: usernameCollisionBody.termsContainerText
228 font.family: usernameCollisionBody.fontFamily
229 font.pixelSize: usernameCollisionBody.fontSize
230 font.bold: usernameCollisionBody.fontBold
231 wrapMode: Text.WordWrap
232 color: hifi.colors.white
233 linkColor: hifi.colors.blueAccent
234 lineHeight: 1
235 lineHeightMode: Text.ProportionalHeight
236
237 onLinkActivated: loginDialog.openUrl(link);
238
239 Component.onCompleted: {
240 if (termsTextMetrics.width > root.bannerWidth) {
241 termsText.width = root.bannerWidth;
242 termsText.wrapMode = Text.WordWrap;
243 additionalText.verticalAlignment = Text.AlignLeft;
244 additionalText.horizontalAlignment = Text.AlignLeft;
245 termsContainer.height = (termsTextMetrics.width / root.bannerWidth) * termsTextMetrics.height;
246 termsContainer.anchors.left = buttons.left;
247 } else {
248 termsText.anchors.centerIn = termsContainer;
249 }
250 }
251 }
252 }
190 }253 }
191 254
192 Component.onCompleted: {255 Component.onCompleted: {
@@ -201,18 +264,25 @@ Item { · 8 unmodified lines
201 target: loginDialog264 target: loginDialog
202 onHandleCreateCompleted: {265 onHandleCreateCompleted: {
203 console.log("Create Succeeded");266 console.log("Create Succeeded");
204 if (usernameCollisionBody.withSteam) {267 if (usernameCollisionBody.withOculus) {
268 if (usernameCollisionBody.loginDialogPoppedUp) {
269 var data = {
270 "action": "user created a profile with Oculus successfully in the username collision screen"
271 }
272 UserActivityLogger.logAction("encourageLoginDialog", data);
273 }
274 loginDialog.loginThroughOculus();
275 } else if (usernameCollisionBody.withSteam) {
205 if (usernameCollisionBody.loginDialogPoppedUp) {276 if (usernameCollisionBody.loginDialogPoppedUp) {
206 var data = {277 var data = {
207 "action": "user created a profile with Steam successfully in the username collision screen"278 "action": "user created a profile with Steam successfully in the username collision screen"
208 }279 }
209 UserActivityLogger.logAction("encourageLoginDialog", data);280 UserActivityLogger.logAction("encourageLoginDialog", data);
210 }281 }
211
212 loginDialog.loginThroughSteam();282 loginDialog.loginThroughSteam();
213 }283 }
214 284 bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": usernameCollisionBody.withSteam,
215 bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": usernameCollisionBody.withSteam, "linkSteam": false })285 "withOculus": usernameCollisionBody.withOculus, "linkSteam": false, "linkOculus": false })
216 }286 }
217 onHandleCreateFailed: {287 onHandleCreateFailed: {
218 console.log("Create Failed: " + error)288 console.log("Create Failed: " + error)
interface/resources/qml/OverlayLoginDialog.qml+1−1
@@ -150,6 +150,6 @@ FocusScope { · 149 unmodified lines
150 150
151 Component.onCompleted: {151 Component.onCompleted: {
152 keyboardTimer.start();152 keyboardTimer.start();
153 bodyLoader.setSource("LoginDialog/LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": false });153 bodyLoader.setSource("LoginDialog/LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": false, "linkOculus": false });
154 }154 }
155}155}
interface/resources/qml/dialogs/TabletLoginDialog.qml+10−6
@@ -14,6 +14,8 @@ import QtQuick 2.5 · 13 unmodified lines
14import controlsUit 1.0 as HifiControlsUit14import controlsUit 1.0 as HifiControlsUit
15import stylesUit 1.0 as HifiStylesUit15import stylesUit 1.0 as HifiStylesUit
16 16
17import TabletScriptingInterface 1.0
18
17import "../LoginDialog"19import "../LoginDialog"
18 20
19FocusScope {21FocusScope {
@@ -25,10 +27,9 @@ FocusScope { · 5 unmodified lines
25 width: parent.width27 width: parent.width
26 height: parent.height28 height: parent.height
27 29
28 signal sendToScript(var message);30 property var tabletProxy: Tablet.getTablet("com.highfidelity.interface.tablet.system");
29 signal canceled();
30 31
31 property bool isHMD: false32 property bool isHMD: HMD.active
32 property bool gotoPreviousApp: false;33 property bool gotoPreviousApp: false;
33 34
34 property bool keyboardEnabled: false35 property bool keyboardEnabled: false
@@ -52,6 +53,7 @@ FocusScope { · 17 unmodified lines
52 }53 }
53 54
54 function tryDestroy() {55 function tryDestroy() {
56 tabletProxy.gotoHomeScreen();
55 }57 }
56 58
57 MouseArea {59 MouseArea {
@@ -76,7 +78,7 @@ FocusScope { · 18 unmodified lines
76 interval: 20078 interval: 200
77 79
78 onTriggered: {80 onTriggered: {
79 if (MenuInterface.isOptionChecked("Use 3D Keyboard")) {81 if (MenuInterface.isOptionChecked("Use 3D Keyboard") && root.isHMD) {
80 KeyboardScriptingInterface.raised = true;82 KeyboardScriptingInterface.raised = true;
81 }83 }
82 }84 }
@@ -169,11 +171,13 @@ FocusScope { · 86 unmodified lines
169 171
170 Component.onDestruction: {172 Component.onDestruction: {
171 loginKeyboard.raised = false;173 loginKeyboard.raised = false;
172 KeyboardScriptingInterface.raised = false;174 if (root.isHMD) {
175 KeyboardScriptingInterface.raised = false;
176 }
173 }177 }
174 178
175 Component.onCompleted: {179 Component.onCompleted: {
176 keyboardTimer.start();180 keyboardTimer.start();
177 bodyLoader.setSource("../LoginDialog/LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": false });181 bodyLoader.setSource("../LoginDialog/LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": false, "linkOculus": false });
178 }182 }
179}183}
interface/src/Application.cpp+6−1
@@ -120,6 +120,7 @@ · 119 unmodified lines
120#include <plugins/PluginManager.h>120#include <plugins/PluginManager.h>
121#include <plugins/PluginUtils.h>121#include <plugins/PluginUtils.h>
122#include <plugins/SteamClientPlugin.h>122#include <plugins/SteamClientPlugin.h>
123#include <plugins/OculusPlatformPlugin.h>
123#include <plugins/InputConfiguration.h>124#include <plugins/InputConfiguration.h>
124#include <RecordingScriptingInterface.h>125#include <RecordingScriptingInterface.h>
125#include <render/EngineStats.h>126#include <render/EngineStats.h>
@@ -800,7 +801,6 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { · 674 unmodified lines
800 if (auto steamClient = pluginManager->getSteamClientPlugin()) {801 if (auto steamClient = pluginManager->getSteamClientPlugin()) {
801 steamClient->init();802 steamClient->init();
802 }803 }
803
804 PROFILE_SET_THREAD_NAME("Main Thread");804 PROFILE_SET_THREAD_NAME("Main Thread");
805 805
806#if defined(Q_OS_WIN)806#if defined(Q_OS_WIN)
@@ -2737,6 +2737,7 @@ Application::~Application() { · 1930 unmodified lines
2737 if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {2737 if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
2738 steamClient->shutdown();2738 steamClient->shutdown();
2739 }2739 }
2740
2740 DependencyManager::destroy<PluginManager>();2741 DependencyManager::destroy<PluginManager>();
2741 2742
2742 DependencyManager::destroy<CompositorHelper>(); // must be destroyed before the FramebufferCache2743 DependencyManager::destroy<CompositorHelper>(); // must be destroyed before the FramebufferCache
@@ -4873,6 +4874,10 @@ void Application::idle() { · 2130 unmodified lines
4873 steamClient->runCallbacks();4874 steamClient->runCallbacks();
4874 }4875 }
4875 4876
4877 if (auto oculusPlugin = PluginManager::getInstance()->getOculusPlatformPlugin()) {
4878 oculusPlugin->handleOVREvents();
4879 }
4880
4876 float secondsSinceLastUpdate = (float)_lastTimeUpdated.nsecsElapsed() / NSECS_PER_MSEC / MSECS_PER_SECOND;4881 float secondsSinceLastUpdate = (float)_lastTimeUpdated.nsecsElapsed() / NSECS_PER_MSEC / MSECS_PER_SECOND;
4877 _lastTimeUpdated.start();4882 _lastTimeUpdated.start();
4878 4883
interface/src/ui/LoginDialog.cpp+126−5
@@ -18,6 +18,7 @@ · 17 unmodified lines
18 18
19#include <plugins/PluginManager.h>19#include <plugins/PluginManager.h>
20#include <plugins/SteamClientPlugin.h>20#include <plugins/SteamClientPlugin.h>
21#include <plugins/OculusPlatformPlugin.h>
21#include <shared/GlobalAppProperties.h>22#include <shared/GlobalAppProperties.h>
22#include <ui/TabletScriptingInterface.h>23#include <ui/TabletScriptingInterface.h>
23#include <UserActivityLogger.h>24#include <UserActivityLogger.h>
@@ -109,8 +110,16 @@ bool LoginDialog::isSteamRunning() const { · 85 unmodified lines
109 return steamClient && steamClient->isRunning();110 return steamClient && steamClient->isRunning();
110}111}
111 112
112bool LoginDialog::isOculusStoreRunning() const {113bool LoginDialog::isOculusRunning() const {
113 return qApp->property(hifi::properties::OCULUS_STORE).toBool();114 auto oculusPlatformPlugin = PluginManager::getInstance()->getOculusPlatformPlugin();
115 return (oculusPlatformPlugin && oculusPlatformPlugin->isRunning());
116}
117
118QString LoginDialog::oculusUserID() const {
119 if (auto oculusPlatformPlugin = PluginManager::getInstance()->getOculusPlatformPlugin()) {
120 return oculusPlatformPlugin->getOculusUserID();
121 }
122 return "";
114}123}
115 124
116void LoginDialog::dismissLoginDialog() {125void LoginDialog::dismissLoginDialog() {
@@ -126,6 +135,79 @@ void LoginDialog::login(const QString& username, const QString& password) const · 9 unmodified lines
126 DependencyManager::get<AccountManager>()->requestAccessToken(username, password);135 DependencyManager::get<AccountManager>()->requestAccessToken(username, password);
127}136}
128 137
138void LoginDialog::loginThroughOculus() {
139 qDebug() << "Attempting to login through Oculus";
140 if (auto oculusPlatformPlugin = PluginManager::getInstance()->getOculusPlatformPlugin()) {
141 oculusPlatformPlugin->requestNonceAndUserID([this] (QString nonce, QString oculusID) {
142 DependencyManager::get<AccountManager>()->requestAccessTokenWithOculus(nonce, oculusID);
143 });
144 }
145}
146
147void LoginDialog::linkOculus() {
148 qDebug() << "Attempting to link Oculus account";
149 if (auto oculusPlatformPlugin = PluginManager::getInstance()->getOculusPlatformPlugin()) {
150 oculusPlatformPlugin->requestNonceAndUserID([this] (QString nonce, QString oculusID) {
151 if (nonce.isEmpty() || oculusID.isEmpty()) {
152 emit handleLoginFailed();
153 return;
154 }
155
156 JSONCallbackParameters callbackParams;
157 callbackParams.callbackReceiver = this;
158 callbackParams.jsonCallbackMethod = "linkCompleted";
159 callbackParams.errorCallbackMethod = "linkFailed";
160 const QString LINK_OCULUS_PATH = "api/v1/user/oculus/link";
161
162 QJsonObject payload;
163 payload["oculus_nonce"] = nonce;
164 payload["oculus_id"] = oculusID;
165
166 auto accountManager = DependencyManager::get<AccountManager>();
167 accountManager->sendRequest(LINK_OCULUS_PATH, AccountManagerAuth::Required,
168 QNetworkAccessManager::PostOperation, callbackParams,
169 QJsonDocument(payload).toJson());
170 });
171 }
172}
173
174void LoginDialog::createAccountFromOculus(QString email, QString username, QString password) {
175 qDebug() << "Attempting to create account from Oculus info";
176 if (auto oculusPlatformPlugin = PluginManager::getInstance()->getOculusPlatformPlugin()) {
177 oculusPlatformPlugin->requestNonceAndUserID([this, email, username, password] (QString nonce, QString oculusID) {
178 if (nonce.isEmpty() || oculusID.isEmpty()) {
179 emit handleLoginFailed();
180 return;
181 }
182
183 JSONCallbackParameters callbackParams;
184 callbackParams.callbackReceiver = this;
185 callbackParams.jsonCallbackMethod = "createCompleted";
186 callbackParams.errorCallbackMethod = "createFailed";
187
188 const QString CREATE_ACCOUNT_FROM_OCULUS_PATH = "api/v1/user/oculus/create";
189
190 QJsonObject payload;
191 payload["oculus_nonce"] = nonce;
192 payload["oculus_id"] = oculusID;
193 if (!email.isEmpty()) {
194 payload["email"] = email;
195 }
196 if (!username.isEmpty()) {
197 payload["username"] = username;
198 }
199 if (!password.isEmpty()) {
200 payload["password"] = password;
201 }
202
203 auto accountManager = DependencyManager::get<AccountManager>();
204 accountManager->sendRequest(CREATE_ACCOUNT_FROM_OCULUS_PATH, AccountManagerAuth::None,
205 QNetworkAccessManager::PostOperation, callbackParams,
206 QJsonDocument(payload).toJson());
207 });
208 }
209}
210
129void LoginDialog::loginThroughSteam() {211void LoginDialog::loginThroughSteam() {
130 qDebug() << "Attempting to login through Steam";212 qDebug() << "Attempting to login through Steam";
131 if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {213 if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
@@ -157,7 +239,7 @@ void LoginDialog::linkSteam() { · 25 unmodified lines
157 const QString LINK_STEAM_PATH = "api/v1/user/steam/link";239 const QString LINK_STEAM_PATH = "api/v1/user/steam/link";
158 240
159 QJsonObject payload;241 QJsonObject payload;
160 payload.insert("steam_auth_ticket", QJsonValue::fromVariant(QVariant(ticket)));242 payload["steam_auth_ticket"] = QJsonValue::fromVariant(QVariant(ticket));
161 243
162 auto accountManager = DependencyManager::get<AccountManager>();244 auto accountManager = DependencyManager::get<AccountManager>();
163 accountManager->sendRequest(LINK_STEAM_PATH, AccountManagerAuth::Required,245 accountManager->sendRequest(LINK_STEAM_PATH, AccountManagerAuth::Required,
@@ -184,9 +266,9 @@ void LoginDialog::createAccountFromSteam(QString username) { · 20 unmodified lines
184 const QString CREATE_ACCOUNT_FROM_STEAM_PATH = "api/v1/user/steam/create";266 const QString CREATE_ACCOUNT_FROM_STEAM_PATH = "api/v1/user/steam/create";
185 267
186 QJsonObject payload;268 QJsonObject payload;
187 payload.insert("steam_auth_ticket", QJsonValue::fromVariant(QVariant(ticket)));269 payload["steam_auth_ticket"] = QJsonValue::fromVariant(QVariant(ticket));
188 if (!username.isEmpty()) {270 if (!username.isEmpty()) {
189 payload.insert("username", QJsonValue::fromVariant(QVariant(username)));271 payload["username"] = username;
190 }272 }
191 273
192 auto accountManager = DependencyManager::get<AccountManager>();274 auto accountManager = DependencyManager::get<AccountManager>();
@@ -214,6 +296,45 @@ void LoginDialog::createCompleted(QNetworkReply* reply) { · 21 unmodified lines
214}296}
215 297
216void LoginDialog::createFailed(QNetworkReply* reply) {298void LoginDialog::createFailed(QNetworkReply* reply) {
299 if (isOculusRunning()) {
300 auto replyData = reply->readAll();
301 QJsonParseError parseError;
302 auto doc = QJsonDocument::fromJson(replyData, &parseError);
303 if (parseError.error != QJsonParseError::NoError) {
304 emit handleCreateFailed(reply->errorString());
305 return;
306 }
307 auto data = doc["data"];
308 auto error = data["error"];
309 auto oculusError = data["oculus"];
310 auto user = error["username"].toArray();
311 auto uid = error["uid"].toArray();
312 auto email = error["email"].toArray();
313 auto password = error["password"].toArray();
314 QString reply;
315 if (uid[0].isString()) {
316 emit handleCreateFailed("Oculus ID " + uid[0].toString() + ".");
317 return;
318 }
319 if (user[0].isString()) {
320 reply = "Username " + user[0].toString() + ".";
321 }
322 if (email[0].isString()) {
323 reply.append((!reply.isEmpty()) ? "\n" : "");
324 reply.append("Email " + email[0].toString() + ".");
325 }
326 if (password[0].isString()) {
327 reply.append((!reply.isEmpty()) ? "\n" : "");
328 reply.append("Password " + password[0].toString() + ".");
329 }
330 if (!oculusError.isNull() && !oculusError.isUndefined()) {
331 emit handleCreateFailed("Could not verify token with Oculus. Please try again.");
332 return;
333 } else {
334 emit handleCreateFailed(reply);
335 return;
336 }
337 }
217 emit handleCreateFailed(reply->errorString());338 emit handleCreateFailed(reply->errorString());
218}339}
219 340
interface/src/ui/LoginDialog.h+6−8
@@ -22,7 +22,6 @@ extern const QUrl OVERLAY_LOGIN_DIALOG; · 21 unmodified lines
22 22
23class LoginDialog : public OffscreenQmlDialog {23class LoginDialog : public OffscreenQmlDialog {
24 Q_OBJECT24 Q_OBJECT
25 Q_PROPERTY(bool isLogIn READ getIsLogIn WRITE setIsLogIn)
26 HIFI_QML_DECL25 HIFI_QML_DECL
27 26
28public:27public:
@@ -67,24 +66,23 @@ protected slots: · 38 unmodified lines
67 Q_INVOKABLE void dismissLoginDialog();66 Q_INVOKABLE void dismissLoginDialog();
68 67
69 Q_INVOKABLE bool isSteamRunning() const;68 Q_INVOKABLE bool isSteamRunning() const;
70 Q_INVOKABLE bool isOculusStoreRunning() const;69 Q_INVOKABLE bool isOculusRunning() const;
70
71 Q_INVOKABLE QString oculusUserID() const;
71 72
72 Q_INVOKABLE void login(const QString& username, const QString& password) const;73 Q_INVOKABLE void login(const QString& username, const QString& password) const;
73 Q_INVOKABLE void loginThroughSteam();74 Q_INVOKABLE void loginThroughSteam();
74 Q_INVOKABLE void linkSteam();75 Q_INVOKABLE void linkSteam();
75 Q_INVOKABLE void createAccountFromSteam(QString username = QString());76 Q_INVOKABLE void createAccountFromSteam(QString username = QString());
77 Q_INVOKABLE void loginThroughOculus();
78 Q_INVOKABLE void linkOculus();
79 Q_INVOKABLE void createAccountFromOculus(QString email = QString(), QString username = QString(), QString password = QString());
76 80
77 Q_INVOKABLE void signup(const QString& email, const QString& username, const QString& password);81 Q_INVOKABLE void signup(const QString& email, const QString& username, const QString& password);
78 82
79 Q_INVOKABLE void openUrl(const QString& url) const;83 Q_INVOKABLE void openUrl(const QString& url) const;
80 84
81 Q_INVOKABLE bool getLoginDialogPoppedUp() const;85 Q_INVOKABLE bool getLoginDialogPoppedUp() const;
82
83private:
84 bool getIsLogIn() const { return _isLogIn; }
85 void setIsLogIn(const bool isLogIn) { _isLogIn = isLogIn; }
86
87 bool _isLogIn{ false };
88};86};
89 87
90#endif // hifi_LoginDialog_h88#endif // hifi_LoginDialog_h
libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h+2−0
@@ -31,6 +31,8 @@ public: · 30 unmodified lines
31 31
32 virtual void compositeExtra() override;32 virtual void compositeExtra() override;
33 33
34 virtual void pluginUpdate() override {};
35
34protected:36protected:
35 mutable bool _isThrottled = false;37 mutable bool _isThrottled = false;
36 38
libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h+1−0
@@ -20,6 +20,7 @@ public: · 19 unmodified lines
20 QImage getScreenshot(float aspectRatio = 0.0f) const override;20 QImage getScreenshot(float aspectRatio = 0.0f) const override;
21 QImage getSecondaryCameraScreenshot() const override;21 QImage getSecondaryCameraScreenshot() const override;
22 void copyTextureToQuickFramebuffer(NetworkTexturePointer source, QOpenGLFramebufferObject* target, GLsync* fenceSync) override {};22 void copyTextureToQuickFramebuffer(NetworkTexturePointer source, QOpenGLFramebufferObject* target, GLsync* fenceSync) override {};
23 void pluginUpdate() override {};
23private:24private:
24 static const QString NAME;25 static const QString NAME;
25};26};
libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h+2−0
@@ -46,6 +46,8 @@ public: · 45 unmodified lines
46 46
47 virtual bool onDisplayTextureReset() override { _clearPreviewFlag = true; return true; };47 virtual bool onDisplayTextureReset() override { _clearPreviewFlag = true; return true; };
48 48
49 void pluginUpdate() override {};
50
49signals:51signals:
50 void hmdMountedChanged();52 void hmdMountedChanged();
51 void hmdVisibleChanged(bool visible);53 void hmdVisibleChanged(bool visible);
libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.h+2−0
@@ -28,6 +28,8 @@ public: · 27 unmodified lines
28 // to the HMD plugins. 28 // to the HMD plugins.
29 //virtual glm::mat4 getEyeToHeadTransform(Eye eye) const override;29 //virtual glm::mat4 getEyeToHeadTransform(Eye eye) const override;
30 30
31 virtual void pluginUpdate() override {};
32
31protected:33protected:
32 virtual bool internalActivate() override;34 virtual bool internalActivate() override;
33 virtual void internalDeactivate() override;35 virtual void internalDeactivate() override;
libraries/networking/src/AccountManager.cpp+23−0
@@ -588,6 +588,29 @@ void AccountManager::requestAccessTokenWithSteam(QByteArray authSessionTicket) { · 587 unmodified lines
588 connect(requestReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(requestAccessTokenError(QNetworkReply::NetworkError)));588 connect(requestReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(requestAccessTokenError(QNetworkReply::NetworkError)));
589}589}
590 590
591void AccountManager::requestAccessTokenWithOculus(const QString& nonce, const QString &oculusID) {
592 QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
593
594 QNetworkRequest request;
595 request.setHeader(QNetworkRequest::UserAgentHeader, _userAgentGetter());
596
597 QUrl grantURL = _authURL;
598 grantURL.setPath("/oauth/token");
599
600 QByteArray postData;
601 postData.append("grant_type=password&");
602 postData.append("oculus_nonce=" + nonce + "&");
603 postData.append("oculus_id=" + oculusID + "&");
604 postData.append("scope=" + ACCOUNT_MANAGER_REQUESTED_SCOPE);
605
606 request.setUrl(grantURL);
607 request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
608
609 QNetworkReply* requestReply = networkAccessManager.post(request, postData);
610 connect(requestReply, &QNetworkReply::finished, this, &AccountManager::requestAccessTokenFinished);
611 connect(requestReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(requestAccessTokenError(QNetworkReply::NetworkError)));
612}
613
591void AccountManager::refreshAccessToken() {614void AccountManager::refreshAccessToken() {
592 615
593 // we can't refresh our access token if we don't have a refresh token, so check for that first616 // we can't refresh our access token if we don't have a refresh token, so check for that first
libraries/networking/src/AccountManager.h+1−0
@@ -106,6 +106,7 @@ public: · 105 unmodified lines
106public slots:106public slots:
107 void requestAccessToken(const QString& login, const QString& password);107 void requestAccessToken(const QString& login, const QString& password);
108 void requestAccessTokenWithSteam(QByteArray authSessionTicket);108 void requestAccessTokenWithSteam(QByteArray authSessionTicket);
109 void requestAccessTokenWithOculus(const QString& nonce, const QString& oculusID);
109 void requestAccessTokenWithAuthCode(const QString& authCode,110 void requestAccessTokenWithAuthCode(const QString& authCode,
110 const QString& clientId,111 const QString& clientId,
111 const QString& clientSecret,112 const QString& clientSecret,
libraries/plugins/src/plugins/DisplayPlugin.h+3−0
@@ -217,6 +217,9 @@ public: · 216 unmodified lines
217 217
218 static const QString& MENU_PATH();218 static const QString& MENU_PATH();
219 219
220 // for updating plugin-related commands. Mimics the input plugin.
221 virtual void pluginUpdate() = 0;
222
220signals:223signals:
221 void recommendedFramebufferSizeChanged(const QSize& size);224 void recommendedFramebufferSizeChanged(const QSize& size);
222 void resetSensorsRequested();225 void resetSensorsRequested();
libraries/plugins/src/plugins/Forward.h+2−0
@@ -21,6 +21,7 @@ class DisplayPlugin; · 20 unmodified lines
21class InputPlugin;21class InputPlugin;
22class CodecPlugin;22class CodecPlugin;
23class SteamClientPlugin;23class SteamClientPlugin;
24class OculusPlatformPlugin;
24class Plugin;25class Plugin;
25class PluginContainer;26class PluginContainer;
26class PluginManager;27class PluginManager;
@@ -35,4 +36,5 @@ using CodecPluginPointer = std::shared_ptr<CodecPlugin>; · 8 unmodified lines
35using CodecPluginList = std::vector<CodecPluginPointer>;36using CodecPluginList = std::vector<CodecPluginPointer>;
36using CodecPluginProvider = std::function<CodecPluginList()>;37using CodecPluginProvider = std::function<CodecPluginList()>;
37using SteamClientPluginPointer = std::shared_ptr<SteamClientPlugin>;38using SteamClientPluginPointer = std::shared_ptr<SteamClientPlugin>;
39using OculusPlatformPluginPointer = std::shared_ptr<OculusPlatformPlugin>;
38using InputPluginSettingsPersister = std::function<void(const InputPluginList&)>;40using InputPluginSettingsPersister = std::function<void(const InputPluginList&)>;
libraries/plugins/src/plugins/OculusPlatformPlugin.h+28−0
@@ -0,0 +1,28 @@
1//
2// Created by Wayne Chen on 2018/12/20
3// Copyright 2018 High Fidelity Inc.
4//
5// Distributed under the Apache License, Version 2.0.
6// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2-0.html
7//
8#pragma once
9
10#include <QtCore/QString>
11
12#include <functional>
13
14using NonceUserIDCallback = std::function<void(QString, QString)>;
15
16class OculusPlatformPlugin {
17public:
18 virtual ~OculusPlatformPlugin() = default;
19
20 virtual QString getName() const = 0;
21 virtual QString getOculusUserID() const = 0;
22
23 virtual bool isRunning() const = 0;
24
25 virtual void requestNonceAndUserID(NonceUserIDCallback callback) = 0;
26
27 virtual void handleOVREvents() = 0;
28};
libraries/plugins/src/plugins/PluginManager.cpp+16−0
@@ -188,6 +188,22 @@ const SteamClientPluginPointer PluginManager::getSteamClientPlugin() { · 187 unmodified lines
188 return steamClientPlugin;188 return steamClientPlugin;
189}189}
190 190
191const OculusPlatformPluginPointer PluginManager::getOculusPlatformPlugin() {
192 static OculusPlatformPluginPointer oculusPlatformPlugin;
193 static std::once_flag once;
194 std::call_once(once, [&] {
195 // Now grab the dynamic plugins
196 for (auto loader : getLoadedPlugins()) {
197 OculusPlatformProvider* oculusPlatformProvider = qobject_cast<OculusPlatformProvider*>(loader->instance());
198 if (oculusPlatformProvider) {
199 oculusPlatformPlugin = oculusPlatformProvider->getOculusPlatformPlugin();
200 break;
201 }
202 }
203 });
204 return oculusPlatformPlugin;
205}
206
191const DisplayPluginList& PluginManager::getDisplayPlugins() {207const DisplayPluginList& PluginManager::getDisplayPlugins() {
192 static std::once_flag once;208 static std::once_flag once;
193 static auto deviceAddedCallback = [](QString deviceName) {209 static auto deviceAddedCallback = [](QString deviceName) {
libraries/plugins/src/plugins/PluginManager.h+1−0
@@ -27,6 +27,7 @@ public: · 26 unmodified lines
27 const InputPluginList& getInputPlugins();27 const InputPluginList& getInputPlugins();
28 const CodecPluginList& getCodecPlugins();28 const CodecPluginList& getCodecPlugins();
29 const SteamClientPluginPointer getSteamClientPlugin();29 const SteamClientPluginPointer getSteamClientPlugin();
30 const OculusPlatformPluginPointer getOculusPlatformPlugin();
30 31
31 DisplayPluginList getPreferredDisplayPlugins();32 DisplayPluginList getPreferredDisplayPlugins();
32 void setPreferredDisplayPlugins(const QStringList& displays);33 void setPreferredDisplayPlugins(const QStringList& displays);
libraries/plugins/src/plugins/RuntimePlugin.h+8−0
@@ -51,5 +51,13 @@ public: · 50 unmodified lines
51 virtual SteamClientPluginPointer getSteamClientPlugin() = 0;51 virtual SteamClientPluginPointer getSteamClientPlugin() = 0;
52};52};
53 53
54class OculusPlatformProvider {
55public:
56 virtual OculusPlatformPluginPointer getOculusPlatformPlugin() = 0;
57};
58
54#define SteamClientProvider_iid "com.highfidelity.plugins.steamclient"59#define SteamClientProvider_iid "com.highfidelity.plugins.steamclient"
55Q_DECLARE_INTERFACE(SteamClientProvider, SteamClientProvider_iid)60Q_DECLARE_INTERFACE(SteamClientProvider, SteamClientProvider_iid)
61
62#define OculusPlatformProvider_iid "com.highfidelity.plugins.oculusplatform"
63Q_DECLARE_INTERFACE(OculusPlatformProvider, OculusPlatformProvider_iid)
plugins/oculus/src/OculusBaseDisplayPlugin.cpp+2−1
@@ -12,6 +12,7 @@ · 11 unmodified lines
12#include <display-plugins/CompositorHelper.h>12#include <display-plugins/CompositorHelper.h>
13#include <gpu/Frame.h>13#include <gpu/Frame.h>
14#include <gl/Config.h>14#include <gl/Config.h>
15#include <shared/GlobalAppProperties.h>
15 16
16#include "OculusHelpers.h"17#include "OculusHelpers.h"
17 18
@@ -30,7 +31,7 @@ bool OculusBaseDisplayPlugin::beginFrameRender(uint32_t frameIndex) { · 12 unmodified lines
30 return false;31 return false;
31 }32 }
32 33
33 if (ovr::quitRequested(status) || ovr::displayLost(status) || !ovr::handleOVREvents()) {34 if (ovr::quitRequested(status) || ovr::displayLost(status)) {
34 QMetaObject::invokeMethod(qApp, "quit");35 QMetaObject::invokeMethod(qApp, "quit");
35 return false;36 return false;
36 }37 }
plugins/oculus/src/OculusBaseDisplayPlugin.h+4−1
@@ -13,6 +13,9 @@ · 12 unmodified lines
13 13
14#include <OVR_CAPI_GL.h>14#include <OVR_CAPI_GL.h>
15 15
16#define OVRPL_DISABLED
17#include <OVR_Platform.h>
18
16class OculusBaseDisplayPlugin : public HmdDisplayPlugin {19class OculusBaseDisplayPlugin : public HmdDisplayPlugin {
17 using Parent = HmdDisplayPlugin;20 using Parent = HmdDisplayPlugin;
18public:21public:
@@ -30,7 +33,7 @@ public: · 11 unmodified lines
30 33
31 QRectF getPlayAreaRect() override;34 QRectF getPlayAreaRect() override;
32 QVector<glm::vec3> getSensorPositions() override;35 QVector<glm::vec3> getSensorPositions() override;
33 36
34protected:37protected:
35 void customizeContext() override;38 void customizeContext() override;
36 void uncustomizeContext() override;39 void uncustomizeContext() override;
plugins/oculus/src/OculusHelpers.cpp+0−31
@@ -296,34 +296,3 @@ controller::Pose hifi::ovr::toControllerPose(ovrHandType hand, · 295 unmodified lines
296 pose.valid = true;296 pose.valid = true;
297 return pose;297 return pose;
298}298}
299
300bool hifi::ovr::handleOVREvents() {
301#ifdef OCULUS_APP_ID
302 if (qApp->property(hifi::properties::OCULUS_STORE).toBool()) {
303 // pop messages to see if we got a return for an entitlement check
304 ovrMessageHandle message = ovr_PopMessage();
305
306 while (message) {
307 switch (ovr_Message_GetType(message)) {
308 case ovrMessage_Entitlement_GetIsViewerEntitled: {
309 if (!ovr_Message_IsError(message)) {
310 // this viewer is entitled, no need to flag anything
311 qCDebug(oculusLog) << "Oculus Platform entitlement check succeeded, proceeding normally";
312 } else {
313 // we failed the entitlement check, quit
314 qCDebug(oculusLog) << "Oculus Platform entitlement check failed, app will now quit" << OCULUS_APP_ID;
315 return false;
316 }
317 }
318 }
319
320 // free the message handle to cleanup and not leak
321 ovr_FreeMessage(message);
322
323 // pop the next message to check, if there is one
324 message = ovr_PopMessage();
325 }
326 }
327#endif
328 return true;
329}
plugins/oculus/src/OculusHelpers.h+0−1
@@ -30,7 +30,6 @@ struct ovr { · 29 unmodified lines
30 static ovrSessionStatus getStatus(ovrResult& result);30 static ovrSessionStatus getStatus(ovrResult& result);
31 static ovrTrackingState getTrackingState(double absTime = 0.0, ovrBool latencyMarker = ovrFalse);31 static ovrTrackingState getTrackingState(double absTime = 0.0, ovrBool latencyMarker = ovrFalse);
32 static QString getError();32 static QString getError();
33 static bool handleOVREvents();
34 33
35 static inline bool quitRequested() { return quitRequested(getStatus()); }34 static inline bool quitRequested() { return quitRequested(getStatus()); }
36 static inline bool reorientRequested() { return reorientRequested(getStatus()); }35 static inline bool reorientRequested() { return reorientRequested(getStatus()); }
plugins/oculus/src/OculusPlatformPlugin.cpp+109−0
@@ -0,0 +1,109 @@
1//
2// Created by Wayne Chen on 2019/01/08
3// Copyright 2019 High Fidelity, Inc.
4//
5// Distributed under the Apache License, Version 2.0.
6// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
7//
8
9#include "OculusPlatformPlugin.h"
10
11#include <shared/GlobalAppProperties.h>
12
13#include <QMetaObject>
14
15#include "OculusHelpers.h"
16
17QString OculusAPIPlugin::NAME { "Oculus Rift" };
18
19OculusAPIPlugin::OculusAPIPlugin() {
20 _session = hifi::ovr::acquireRenderSession();
21}
22
23OculusAPIPlugin::~OculusAPIPlugin() {
24 hifi::ovr::releaseRenderSession(_session);
25}
26
27bool OculusAPIPlugin::isRunning() const {
28 return (qApp->property(hifi::properties::OCULUS_STORE).toBool());
29}
30
31void OculusAPIPlugin::requestNonceAndUserID(NonceUserIDCallback callback) {
32#ifdef OCULUS_APP_ID
33 _nonceUserIDCallback = callback;
34 ovr_User_GetUserProof();
35 ovr_User_GetLoggedInUser();
36#endif
37}
38
39void OculusAPIPlugin::handleOVREvents() {
40#ifdef OCULUS_APP_ID
41 if (qApp->property(hifi::properties::OCULUS_STORE).toBool()) {
42 // pop messages to see if we got a return for an entitlement check
43 ovrMessageHandle message { nullptr };
44
45 // pop the next message to check, if there is one
46 while ((message = ovr_PopMessage())) {
47 switch (ovr_Message_GetType(message)) {
48 case ovrMessage_Entitlement_GetIsViewerEntitled: {
49 if (!ovr_Message_IsError(message)) {
50 // this viewer is entitled, no need to flag anything
51 qCDebug(oculusLog) << "Oculus Platform entitlement check succeeded, proceeding normally";
52 } else {
53 // we failed the entitlement check, quit
54 qCDebug(oculusLog) << "Oculus Platform entitlement check failed, app will now quit" << OCULUS_APP_ID;
55 QMetaObject::invokeMethod(qApp, "quit");
56 }
57 break;
58 }
59 case ovrMessage_User_Get: {
60 if (!ovr_Message_IsError(message)) {
61 qCDebug(oculusLog) << "Oculus Platform user retrieval succeeded";
62 ovrUserHandle user = ovr_Message_GetUser(message);
63 _user = ovr_User_GetOculusID(user);
64 // went all the way through the `requestNonceAndUserID()` pipeline successfully.
65 } else {
66 qCDebug(oculusLog) << "Oculus Platform user retrieval failed" << QString(ovr_Error_GetMessage(ovr_Message_GetError(message)));
67 // emit the signal so we don't hang for it anywhere else.
68 _user = "";
69 }
70 break;
71 }
72 case ovrMessage_User_GetLoggedInUser: {
73 if (!ovr_Message_IsError(message)) {
74 ovrUserHandle user = ovr_Message_GetUser(message);
75 _userID = ovr_User_GetID(user);
76 ovr_User_Get(_userID);
77 } else {
78 qCDebug(oculusLog) << "Oculus Platform user ID retrieval failed" << QString(ovr_Error_GetMessage(ovr_Message_GetError(message)));
79 // emit the signal so we don't hang for it anywhere else.
80 }
81 _userIDChanged = true;
82 break;
83 }
84 case ovrMessage_User_GetUserProof: {
85 if (!ovr_Message_IsError(message)) {
86 ovrUserProofHandle userProof = ovr_Message_GetUserProof(message);
87 _nonce = ovr_UserProof_GetNonce(userProof);
88 qCDebug(oculusLog) << "Oculus Platform nonce retrieval succeeded: " << _nonce;
89 } else {
90 qCDebug(oculusLog) << "Oculus Platform nonce retrieval failed" << QString(ovr_Error_GetMessage(ovr_Message_GetError(message)));
91 _nonce = "";
92 // emit the signal so we don't hang for it anywhere else.
93 }
94 _nonceChanged = true;
95 break;
96 }
97 }
98
99 if (_nonceChanged && _userIDChanged) {
100 _nonceUserIDCallback(_nonce, QString::number(_userID));
101 _nonceChanged = _userIDChanged = false;
102 }
103
104 // free the message handle to cleanup and not leak
105 ovr_FreeMessage(message);
106 }
107 }
108#endif
109}
plugins/oculus/src/OculusPlatformPlugin.h+39−0
@@ -0,0 +1,39 @@
1//
2// Created by Wayne Chen on 2019/01/08
3// Copyright 2019 High Fidelity, Inc.
4//
5// Distributed under the Apache License, Version 2.0.
6// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
7//
8#pragma once
9
10#include <plugins/OculusPlatformPlugin.h>
11
12#include <OVR_CAPI_GL.h>
13
14#define OVRPL_DISABLED
15#include <OVR_Platform.h>
16
17class OculusAPIPlugin : public OculusPlatformPlugin {
18public:
19 OculusAPIPlugin();
20 virtual ~OculusAPIPlugin();
21 QString getName() const { return NAME; }
22 QString getOculusUserID() const { return _user; };
23
24 bool isRunning() const;
25
26 virtual void requestNonceAndUserID(NonceUserIDCallback callback);
27
28 virtual void handleOVREvents();
29
30private:
31 static QString NAME;
32 NonceUserIDCallback _nonceUserIDCallback;
33 QString _nonce;
34 bool _nonceChanged{ false };
35 bool _userIDChanged{ false };
36 QString _user;
37 ovrID _userID;
38 ovrSession _session;
39};
plugins/oculus/src/OculusProvider.cpp+14−1
@@ -18,15 +18,18 @@ · 17 unmodified lines
18 18
19#include "OculusDisplayPlugin.h"19#include "OculusDisplayPlugin.h"
20#include "OculusDebugDisplayPlugin.h"20#include "OculusDebugDisplayPlugin.h"
21#include "OculusPlatformPlugin.h"
21#include "OculusControllerManager.h"22#include "OculusControllerManager.h"
22 23
23class OculusProvider : public QObject, public DisplayProvider, InputProvider24class OculusProvider : public QObject, public DisplayProvider, InputProvider, OculusPlatformProvider
24{25{
25 Q_OBJECT26 Q_OBJECT
26 Q_PLUGIN_METADATA(IID DisplayProvider_iid FILE "oculus.json")27 Q_PLUGIN_METADATA(IID DisplayProvider_iid FILE "oculus.json")
27 Q_INTERFACES(DisplayProvider)28 Q_INTERFACES(DisplayProvider)
28 Q_PLUGIN_METADATA(IID InputProvider_iid FILE "oculus.json")29 Q_PLUGIN_METADATA(IID InputProvider_iid FILE "oculus.json")
29 Q_INTERFACES(InputProvider)30 Q_INTERFACES(InputProvider)
31 Q_PLUGIN_METADATA(IID OculusPlatformProvider_iid FILE "oculus.json")
32 Q_INTERFACES(OculusPlatformProvider)
30 33
31public:34public:
32 OculusProvider(QObject* parent = nullptr) : QObject(parent) {}35 OculusProvider(QObject* parent = nullptr) : QObject(parent) {}
@@ -62,6 +65,15 @@ public: · 29 unmodified lines
62 return _inputPlugins;65 return _inputPlugins;
63 }66 }
64 67
68 virtual OculusPlatformPluginPointer getOculusPlatformPlugin() override {
69 static std::once_flag once;
70 std::call_once(once, [&] {
71 _oculusPlatformPlugin = std::make_shared<OculusAPIPlugin>();
72
73 });
74 return _oculusPlatformPlugin;
75 }
76
65 virtual void destroyInputPlugins() override {77 virtual void destroyInputPlugins() override {
66 _inputPlugins.clear();78 _inputPlugins.clear();
67 }79 }
@@ -73,6 +85,7 @@ public: · 5 unmodified lines
73private:85private:
74 DisplayPluginList _displayPlugins;86 DisplayPluginList _displayPlugins;
75 InputPluginList _inputPlugins;87 InputPluginList _inputPlugins;
88 OculusPlatformPluginPointer _oculusPlatformPlugin;
76};89};
77 90
78#include "OculusProvider.moc"91#include "OculusProvider.moc"