mirror of
https://github.com/lubosz/overte.git
synced 2025-04-16 09:29:16 +02:00
commit
5a1c7bd4e6
42 changed files with 1752 additions and 343 deletions
BIN
interface/resources/images/steam-sign-in.png
Normal file
BIN
interface/resources/images/steam-sign-in.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.7 KiB |
|
@ -10,296 +10,70 @@
|
|||
|
||||
import Hifi 1.0
|
||||
import QtQuick 2.4
|
||||
import "controls"
|
||||
import "styles"
|
||||
|
||||
import "controls-uit"
|
||||
import "styles-uit"
|
||||
import "windows"
|
||||
|
||||
ScrollingWindow {
|
||||
import "LoginDialog"
|
||||
|
||||
ModalWindow {
|
||||
id: root
|
||||
HifiConstants { id: hifi }
|
||||
objectName: "LoginDialog"
|
||||
height: loginDialog.implicitHeight
|
||||
width: loginDialog.implicitWidth
|
||||
// FIXME make movable
|
||||
anchors.centerIn: parent
|
||||
destroyOnHidden: false
|
||||
hideBackground: true
|
||||
shown: false
|
||||
implicitWidth: 520
|
||||
implicitHeight: 320
|
||||
destroyOnCloseButton: true
|
||||
destroyOnHidden: true
|
||||
visible: true
|
||||
|
||||
property string iconText: ""
|
||||
property int iconSize: 50
|
||||
|
||||
property string title: ""
|
||||
property int titleWidth: 0
|
||||
|
||||
LoginDialog {
|
||||
id: loginDialog
|
||||
implicitWidth: backgroundRectangle.width
|
||||
implicitHeight: backgroundRectangle.height
|
||||
readonly property int inputWidth: 500
|
||||
readonly property int inputHeight: 60
|
||||
readonly property int borderWidth: 30
|
||||
readonly property int closeMargin: 16
|
||||
readonly property real tan30: 0.577 // tan(30°)
|
||||
readonly property int inputSpacing: 16
|
||||
|
||||
Rectangle {
|
||||
id: backgroundRectangle
|
||||
width: loginDialog.inputWidth + loginDialog.borderWidth * 2
|
||||
height: loginDialog.inputHeight * 6 + loginDialog.closeMargin * 2
|
||||
radius: loginDialog.closeMargin * 2
|
||||
color: "#2c86b1"
|
||||
opacity: 0.85
|
||||
}
|
||||
|
||||
Column {
|
||||
id: mainContent
|
||||
width: loginDialog.inputWidth
|
||||
spacing: loginDialog.inputSpacing
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Item {
|
||||
// Offset content down a little
|
||||
width: loginDialog.inputWidth
|
||||
height: loginDialog.closeMargin
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: loginDialog.inputWidth
|
||||
height: loginDialog.inputHeight
|
||||
radius: height / 2
|
||||
color: "#ebebeb"
|
||||
|
||||
Image {
|
||||
source: "../images/login-username.svg"
|
||||
width: loginDialog.inputHeight * 0.65
|
||||
height: width
|
||||
sourceSize: Qt.size(width, height);
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter
|
||||
left: parent.left
|
||||
leftMargin: loginDialog.inputHeight / 4
|
||||
}
|
||||
}
|
||||
|
||||
TextInput {
|
||||
id: username
|
||||
anchors {
|
||||
fill: parent
|
||||
leftMargin: loginDialog.inputHeight
|
||||
rightMargin: loginDialog.inputHeight / 2
|
||||
}
|
||||
|
||||
helperText: "username or email"
|
||||
color: hifi.colors.text
|
||||
|
||||
KeyNavigation.tab: password
|
||||
KeyNavigation.backtab: password
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: loginDialog.inputWidth
|
||||
height: loginDialog.inputHeight
|
||||
radius: height / 2
|
||||
color: "#ebebeb"
|
||||
|
||||
Image {
|
||||
source: "../images/login-password.svg"
|
||||
width: loginDialog.inputHeight * 0.65
|
||||
height: width
|
||||
sourceSize: Qt.size(width, height);
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter
|
||||
left: parent.left
|
||||
leftMargin: loginDialog.inputHeight / 4
|
||||
}
|
||||
}
|
||||
|
||||
TextInput {
|
||||
id: password
|
||||
anchors {
|
||||
fill: parent
|
||||
leftMargin: loginDialog.inputHeight
|
||||
rightMargin: loginDialog.inputHeight / 2
|
||||
}
|
||||
|
||||
helperText: "password"
|
||||
echoMode: TextInput.Password
|
||||
color: hifi.colors.text
|
||||
|
||||
KeyNavigation.tab: username
|
||||
KeyNavigation.backtab: username
|
||||
onFocusChanged: {
|
||||
if (password.focus) {
|
||||
password.selectAll()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: loginDialog.inputWidth
|
||||
height: loginDialog.inputHeight / 2
|
||||
|
||||
Text {
|
||||
id: messageText
|
||||
|
||||
visible: loginDialog.statusText != "" && loginDialog.statusText != "Logging in..."
|
||||
|
||||
width: loginDialog.inputWidth
|
||||
height: loginDialog.inputHeight / 2
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
||||
text: loginDialog.statusText
|
||||
color: "white"
|
||||
}
|
||||
|
||||
Row {
|
||||
id: messageSpinner
|
||||
|
||||
visible: loginDialog.statusText == "Logging in..."
|
||||
onVisibleChanged: visible ? messageSpinnerAnimation.restart() : messageSpinnerAnimation.stop()
|
||||
|
||||
spacing: 24
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: spinner1
|
||||
width: 10
|
||||
height: 10
|
||||
color: "#ebebeb"
|
||||
opacity: 0.05
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: spinner2
|
||||
width: 10
|
||||
height: 10
|
||||
color: "#ebebeb"
|
||||
opacity: 0.05
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: spinner3
|
||||
width: 10
|
||||
height: 10
|
||||
color: "#ebebeb"
|
||||
opacity: 0.05
|
||||
}
|
||||
|
||||
SequentialAnimation {
|
||||
id: messageSpinnerAnimation
|
||||
running: messageSpinner.visible
|
||||
loops: Animation.Infinite
|
||||
NumberAnimation { target: spinner1; property: "opacity"; to: 1.0; duration: 1000 }
|
||||
NumberAnimation { target: spinner2; property: "opacity"; to: 1.0; duration: 1000 }
|
||||
NumberAnimation { target: spinner3; property: "opacity"; to: 1.0; duration: 1000 }
|
||||
NumberAnimation { target: spinner1; property: "opacity"; to: 0.05; duration: 0 }
|
||||
NumberAnimation { target: spinner2; property: "opacity"; to: 0.05; duration: 0 }
|
||||
NumberAnimation { target: spinner3; property: "opacity"; to: 0.05; duration: 0 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: loginDialog.inputWidth
|
||||
height: loginDialog.inputHeight
|
||||
radius: height / 2
|
||||
color: "#353535"
|
||||
|
||||
TextInput {
|
||||
anchors.fill: parent
|
||||
text: "Login"
|
||||
color: "white"
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
loginDialog.login(username.text, password.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors { left: parent.left; right: parent.right; }
|
||||
height: loginDialog.inputHeight
|
||||
|
||||
Image {
|
||||
id: hifiIcon
|
||||
source: "../images/hifi-logo-blackish.svg"
|
||||
width: loginDialog.inputHeight
|
||||
height: width
|
||||
sourceSize: Qt.size(width, height);
|
||||
anchors { verticalCenter: parent.verticalCenter; horizontalCenter: parent.horizontalCenter }
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors { verticalCenter: parent.verticalCenter; right: hifiIcon.left; margins: loginDialog.inputSpacing }
|
||||
text: "Password?"
|
||||
scale: 0.8
|
||||
font.underline: true
|
||||
color: "#e0e0e0"
|
||||
MouseArea {
|
||||
anchors { fill: parent; margins: -loginDialog.inputSpacing / 2 }
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: loginDialog.openUrl(loginDialog.rootUrl + "/users/password/new")
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors { verticalCenter: parent.verticalCenter; left: hifiIcon.right; margins: loginDialog.inputSpacing }
|
||||
text: "Register"
|
||||
scale: 0.8
|
||||
font.underline: true
|
||||
color: "#e0e0e0"
|
||||
|
||||
MouseArea {
|
||||
anchors { fill: parent; margins: -loginDialog.inputSpacing / 2 }
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: loginDialog.openUrl(loginDialog.rootUrl + "/signup")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onShownChanged: {
|
||||
if (!shown) {
|
||||
username.text = ""
|
||||
password.text = ""
|
||||
loginDialog.statusText = ""
|
||||
} else {
|
||||
username.forceActiveFocus()
|
||||
Loader {
|
||||
id: bodyLoader
|
||||
anchors.fill: parent
|
||||
source: loginDialog.isSteamRunning() ? "LoginDialog/SignInBody.qml" : "LoginDialog/LinkAccountBody.qml"
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onPressed: {
|
||||
switch (event.key) {
|
||||
if (!visible) {
|
||||
return
|
||||
}
|
||||
|
||||
if (event.modifiers === Qt.ControlModifier)
|
||||
switch (event.key) {
|
||||
case Qt.Key_A:
|
||||
event.accepted = true
|
||||
detailedText.selectAll()
|
||||
break
|
||||
case Qt.Key_C:
|
||||
event.accepted = true
|
||||
detailedText.copy()
|
||||
break
|
||||
case Qt.Key_Period:
|
||||
if (Qt.platform.os === "osx") {
|
||||
event.accepted = true
|
||||
content.reject()
|
||||
}
|
||||
break
|
||||
} else switch (event.key) {
|
||||
case Qt.Key_Escape:
|
||||
case Qt.Key_Back:
|
||||
root.shown = false;
|
||||
event.accepted = true;
|
||||
break;
|
||||
event.accepted = true
|
||||
destroy()
|
||||
break
|
||||
|
||||
case Qt.Key_Enter:
|
||||
case Qt.Key_Return:
|
||||
if (username.activeFocus) {
|
||||
event.accepted = true
|
||||
password.forceActiveFocus()
|
||||
} else if (password.activeFocus) {
|
||||
event.accepted = true
|
||||
if (username.text == "") {
|
||||
username.forceActiveFocus()
|
||||
} else {
|
||||
loginDialog.login(username.text, password.text)
|
||||
}
|
||||
}
|
||||
event.accepted = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
125
interface/resources/qml/LoginDialog/CompleteProfileBody.qml
Normal file
125
interface/resources/qml/LoginDialog/CompleteProfileBody.qml
Normal file
|
@ -0,0 +1,125 @@
|
|||
//
|
||||
// CompleteProfileBody.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import Hifi 1.0
|
||||
import QtQuick 2.4
|
||||
import QtQuick.Controls.Styles 1.4 as OriginalStyles
|
||||
|
||||
import "../controls-uit"
|
||||
import "../styles-uit"
|
||||
|
||||
Item {
|
||||
id: completeProfileBody
|
||||
clip: true
|
||||
width: pane.width
|
||||
height: pane.height
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
readonly property int minWidth: 480
|
||||
readonly property int maxWidth: 1280
|
||||
readonly property int minHeight: 120
|
||||
readonly property int maxHeight: 720
|
||||
|
||||
function resize() {
|
||||
var targetWidth = Math.max(titleWidth, additionalTextContainer.contentWidth)
|
||||
var targetHeight = 4 * hifi.dimensions.contentSpacing.y + buttons.height + additionalTextContainer.height
|
||||
|
||||
root.width = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth))
|
||||
root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight))
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: buttons
|
||||
anchors {
|
||||
top: parent.top
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
margins: 0
|
||||
topMargin: 3 * hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
spacing: hifi.dimensions.contentSpacing.x
|
||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||
|
||||
Button {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 200
|
||||
|
||||
text: qsTr("Create your profile")
|
||||
color: hifi.buttons.blue
|
||||
|
||||
onClicked: loginDialog.createAccountFromStream()
|
||||
}
|
||||
|
||||
Button {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
text: qsTr("Cancel")
|
||||
|
||||
|
||||
onClicked: root.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
ShortcutText {
|
||||
id: additionalTextContainer
|
||||
anchors {
|
||||
top: buttons.bottom
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
margins: 0
|
||||
topMargin: hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
|
||||
text: "<a href='https://fake.link'>Already have a High Fidelity profile? Link to an existing profile here.</a>"
|
||||
|
||||
wrapMode: Text.WordWrap
|
||||
lineHeight: 2
|
||||
lineHeightMode: Text.ProportionalHeight
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
|
||||
onLinkActivated: {
|
||||
bodyLoader.source = "LinkAccountBody.qml"
|
||||
bodyLoader.item.width = root.pane.width
|
||||
bodyLoader.item.height = root.pane.height
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
root.title = qsTr("Complete Your Profile")
|
||||
root.iconText = "<"
|
||||
d.resize();
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: loginDialog
|
||||
onHandleCreateCompleted: {
|
||||
console.log("Create Succeeded")
|
||||
|
||||
loginDialog.loginThroughSteam()
|
||||
}
|
||||
onHandleCreateFailed: {
|
||||
console.log("Create Failed: " + error)
|
||||
|
||||
bodyLoader.source = "UsernameCollisionBody.qml"
|
||||
bodyLoader.item.width = root.pane.width
|
||||
bodyLoader.item.height = root.pane.height
|
||||
}
|
||||
onHandleLoginCompleted: {
|
||||
console.log("Login Succeeded")
|
||||
|
||||
bodyLoader.setSource("WelcomeBody.qml", { "welcomeBack" : false })
|
||||
bodyLoader.item.width = root.pane.width
|
||||
bodyLoader.item.height = root.pane.height
|
||||
}
|
||||
onHandleLoginFailed: {
|
||||
console.log("Login Failed")
|
||||
}
|
||||
}
|
||||
}
|
215
interface/resources/qml/LoginDialog/LinkAccountBody.qml
Normal file
215
interface/resources/qml/LoginDialog/LinkAccountBody.qml
Normal file
|
@ -0,0 +1,215 @@
|
|||
//
|
||||
// LinkAccountBody.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import Hifi 1.0
|
||||
import QtQuick 2.4
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4 as OriginalStyles
|
||||
|
||||
import "../controls-uit"
|
||||
import "../styles-uit"
|
||||
|
||||
Item {
|
||||
id: linkAccountBody
|
||||
clip: true
|
||||
width: root.pane.width
|
||||
height: root.pane.height
|
||||
|
||||
function login() {
|
||||
mainTextContainer.visible = false
|
||||
loginDialog.login(usernameField.text, passwordField.text)
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
readonly property int minWidth: 480
|
||||
readonly property int maxWidth: 1280
|
||||
readonly property int minHeight: 120
|
||||
readonly property int maxHeight: 720
|
||||
|
||||
function resize() {
|
||||
var targetWidth = Math.max(titleWidth, form.contentWidth)
|
||||
var targetHeight = hifi.dimensions.contentSpacing.y + mainTextContainer.height +
|
||||
4 * hifi.dimensions.contentSpacing.y + form.height +
|
||||
4 * hifi.dimensions.contentSpacing.y + buttons.height
|
||||
|
||||
root.width = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth))
|
||||
root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight))
|
||||
}
|
||||
}
|
||||
|
||||
ShortcutText {
|
||||
id: mainTextContainer
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
margins: 0
|
||||
topMargin: hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
|
||||
visible: false
|
||||
|
||||
text: qsTr("Username or password incorrect.")
|
||||
wrapMode: Text.WordWrap
|
||||
color: hifi.colors.redAccent
|
||||
lineHeight: 1
|
||||
lineHeightMode: Text.ProportionalHeight
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
Column {
|
||||
id: form
|
||||
anchors {
|
||||
top: mainTextContainer.bottom
|
||||
left: parent.left
|
||||
margins: 0
|
||||
topMargin: 2 * hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
spacing: 2 * hifi.dimensions.contentSpacing.y
|
||||
|
||||
Row {
|
||||
spacing: hifi.dimensions.contentSpacing.x
|
||||
|
||||
TextField {
|
||||
id: usernameField
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
width: 350
|
||||
|
||||
label: "User Name or Email"
|
||||
}
|
||||
|
||||
ShortcutText {
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
text: "<a href='https://highfidelity.com/users/password/new'>Forgot Username?</a>"
|
||||
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
|
||||
onLinkActivated: loginDialog.openUrl(link)
|
||||
}
|
||||
}
|
||||
Row {
|
||||
spacing: hifi.dimensions.contentSpacing.x
|
||||
|
||||
TextField {
|
||||
id: passwordField
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
width: 350
|
||||
|
||||
label: "Password"
|
||||
echoMode: TextInput.Password
|
||||
}
|
||||
|
||||
ShortcutText {
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
text: "<a href='https://highfidelity.com/users/password/new'>Forgot Password?</a>"
|
||||
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
|
||||
onLinkActivated: loginDialog.openUrl(link)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Row {
|
||||
id: buttons
|
||||
anchors {
|
||||
top: form.bottom
|
||||
right: parent.right
|
||||
margins: 0
|
||||
topMargin: 3 * hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
spacing: hifi.dimensions.contentSpacing.x
|
||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||
|
||||
Button {
|
||||
id: linkAccountButton
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 200
|
||||
|
||||
text: qsTr(loginDialog.isSteamRunning() ? "Link Account" : "Login")
|
||||
color: hifi.buttons.blue
|
||||
|
||||
onClicked: linkAccountBody.login()
|
||||
}
|
||||
|
||||
Button {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
text: qsTr("Cancel")
|
||||
|
||||
onClicked: root.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
root.title = qsTr("Sign Into High Fidelity")
|
||||
root.iconText = "<"
|
||||
d.resize();
|
||||
|
||||
usernameField.forceActiveFocus()
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: loginDialog
|
||||
onHandleLoginCompleted: {
|
||||
console.log("Login Succeeded, linking steam account")
|
||||
|
||||
if (loginDialog.isSteamRunning()) {
|
||||
loginDialog.linkSteam()
|
||||
} else {
|
||||
bodyLoader.setSource("WelcomeBody.qml", { "welcomeBack" : true })
|
||||
bodyLoader.item.width = root.pane.width
|
||||
bodyLoader.item.height = root.pane.height
|
||||
}
|
||||
}
|
||||
onHandleLoginFailed: {
|
||||
console.log("Login Failed")
|
||||
mainTextContainer.visible = true
|
||||
}
|
||||
onHandleLinkCompleted: {
|
||||
console.log("Link Succeeded")
|
||||
|
||||
bodyLoader.setSource("WelcomeBody.qml", { "welcomeBack" : true })
|
||||
bodyLoader.item.width = root.pane.width
|
||||
bodyLoader.item.height = root.pane.height
|
||||
}
|
||||
onHandleLinkFailed: {
|
||||
console.log("Link Failed")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onPressed: {
|
||||
if (!visible) {
|
||||
return
|
||||
}
|
||||
|
||||
switch (event.key) {
|
||||
case Qt.Key_Enter:
|
||||
case Qt.Key_Return:
|
||||
event.accepted = true
|
||||
linkAccountBody.login()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
128
interface/resources/qml/LoginDialog/SignInBody.qml
Normal file
128
interface/resources/qml/LoginDialog/SignInBody.qml
Normal file
|
@ -0,0 +1,128 @@
|
|||
//
|
||||
// SignInBody.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import Hifi 1.0
|
||||
import QtQuick 2.4
|
||||
import QtQuick.Controls.Styles 1.4 as OriginalStyles
|
||||
|
||||
import "../controls-uit"
|
||||
import "../styles-uit"
|
||||
|
||||
Item {
|
||||
id: signInBody
|
||||
clip: true
|
||||
width: pane.width
|
||||
height: pane.height
|
||||
|
||||
property bool required: false
|
||||
|
||||
function login() {
|
||||
console.log("Trying to log in")
|
||||
loginDialog.loginThroughSteam()
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
root.destroy()
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
readonly property int minWidth: 480
|
||||
readonly property int maxWidth: 1280
|
||||
readonly property int minHeight: 120
|
||||
readonly property int maxHeight: 720
|
||||
|
||||
function resize() {
|
||||
var targetWidth = Math.max(titleWidth, mainTextContainer.contentWidth)
|
||||
var targetHeight = mainTextContainer.height + 3 * hifi.dimensions.contentSpacing.y + buttons.height
|
||||
|
||||
root.width = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth))
|
||||
root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight))
|
||||
}
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
id: mainTextContainer
|
||||
anchors {
|
||||
top: parent.top
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
margins: 0
|
||||
topMargin: hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
|
||||
text: required ? qsTr("This domain's owner requires that you sign in:")
|
||||
: qsTr("Sign in to access your user account:")
|
||||
wrapMode: Text.WordWrap
|
||||
color: hifi.colors.baseGrayHighlight
|
||||
lineHeight: 2
|
||||
lineHeightMode: Text.ProportionalHeight
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
Row {
|
||||
id: buttons
|
||||
anchors {
|
||||
top: mainTextContainer.bottom
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
margins: 0
|
||||
topMargin: 2 * hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
spacing: hifi.dimensions.contentSpacing.x
|
||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||
|
||||
Button {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
width: undefined // invalidate so that the image's size sets the width
|
||||
height: undefined // invalidate so that the image's size sets the height
|
||||
focus: true
|
||||
|
||||
style: OriginalStyles.ButtonStyle {
|
||||
background: Image {
|
||||
id: buttonImage
|
||||
source: "../../images/steam-sign-in.png"
|
||||
}
|
||||
}
|
||||
onClicked: signInBody.login()
|
||||
}
|
||||
Button {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
text: qsTr("Cancel");
|
||||
|
||||
onClicked: signInBody.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
root.title = required ? qsTr("Sign In Required")
|
||||
: qsTr("Sign In")
|
||||
root.iconText = ""
|
||||
d.resize();
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: loginDialog
|
||||
onHandleLoginCompleted: {
|
||||
console.log("Login Succeeded")
|
||||
|
||||
bodyLoader.setSource("WelcomeBody.qml", { "welcomeBack" : true })
|
||||
bodyLoader.item.width = root.pane.width
|
||||
bodyLoader.item.height = root.pane.height
|
||||
}
|
||||
onHandleLoginFailed: {
|
||||
console.log("Login Failed")
|
||||
|
||||
bodyLoader.source = "CompleteProfileBody.qml"
|
||||
bodyLoader.item.width = root.pane.width
|
||||
bodyLoader.item.height = root.pane.height
|
||||
}
|
||||
}
|
||||
}
|
173
interface/resources/qml/LoginDialog/UsernameCollisionBody.qml
Normal file
173
interface/resources/qml/LoginDialog/UsernameCollisionBody.qml
Normal file
|
@ -0,0 +1,173 @@
|
|||
//
|
||||
// UsernameCollisionBody.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import Hifi 1.0
|
||||
import QtQuick 2.4
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4 as OriginalStyles
|
||||
|
||||
import "../controls-uit"
|
||||
import "../styles-uit"
|
||||
|
||||
Item {
|
||||
id: usernameCollisionBody
|
||||
clip: true
|
||||
width: root.pane.width
|
||||
height: root.pane.height
|
||||
|
||||
function create() {
|
||||
mainTextContainer.visible = false
|
||||
loginDialog.createAccountFromStream(textField.text)
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
readonly property int minWidth: 480
|
||||
readonly property int maxWidth: 1280
|
||||
readonly property int minHeight: 120
|
||||
readonly property int maxHeight: 720
|
||||
|
||||
function resize() {
|
||||
var targetWidth = Math.max(titleWidth, Math.max(mainTextContainer.contentWidth,
|
||||
termsContainer.contentWidth))
|
||||
var targetHeight = mainTextContainer.height +
|
||||
2 * hifi.dimensions.contentSpacing.y + textField.height +
|
||||
5 * hifi.dimensions.contentSpacing.y + termsContainer.height +
|
||||
1 * hifi.dimensions.contentSpacing.y + buttons.height
|
||||
|
||||
root.width = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth))
|
||||
root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight))
|
||||
}
|
||||
}
|
||||
|
||||
ShortcutText {
|
||||
id: mainTextContainer
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
margins: 0
|
||||
topMargin: hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
|
||||
text: qsTr("Your Steam username is not available.")
|
||||
wrapMode: Text.WordWrap
|
||||
color: hifi.colors.redAccent
|
||||
lineHeight: 1
|
||||
lineHeightMode: Text.ProportionalHeight
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
|
||||
TextField {
|
||||
id: textField
|
||||
anchors {
|
||||
top: mainTextContainer.bottom
|
||||
left: parent.left
|
||||
margins: 0
|
||||
topMargin: 2 * hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
width: 250
|
||||
|
||||
placeholderText: "Choose your own"
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
id: termsContainer
|
||||
anchors {
|
||||
top: textField.bottom
|
||||
left: parent.left
|
||||
margins: 0
|
||||
topMargin: 3 * hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
|
||||
text: qsTr("By creating this user profile, you agree to <a href='https://highfidelity.com/terms'>High Fidelity's Terms of Service</a>")
|
||||
wrapMode: Text.WordWrap
|
||||
color: hifi.colors.baseGrayHighlight
|
||||
lineHeight: 1
|
||||
lineHeightMode: Text.ProportionalHeight
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
|
||||
onLinkActivated: loginDialog.openUrl(link)
|
||||
}
|
||||
|
||||
Row {
|
||||
id: buttons
|
||||
anchors {
|
||||
top: termsContainer.bottom
|
||||
right: parent.right
|
||||
margins: 0
|
||||
topMargin: 1 * hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
spacing: hifi.dimensions.contentSpacing.x
|
||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||
|
||||
Button {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 200
|
||||
|
||||
text: qsTr("Create your profile")
|
||||
color: hifi.buttons.blue
|
||||
|
||||
onClicked: usernameCollisionBody.create()
|
||||
}
|
||||
|
||||
Button {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
text: qsTr("Cancel")
|
||||
|
||||
onClicked: root.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
root.title = qsTr("Complete Your Profile")
|
||||
root.iconText = "<"
|
||||
d.resize();
|
||||
}
|
||||
Connections {
|
||||
target: loginDialog
|
||||
onHandleCreateCompleted: {
|
||||
console.log("Create Succeeded")
|
||||
|
||||
loginDialog.loginThroughSteam()
|
||||
}
|
||||
onHandleCreateFailed: {
|
||||
console.log("Create Failed: " + error)
|
||||
|
||||
mainTextContainer.visible = true
|
||||
mainTextContainer.text = "\"" + textField.text + qsTr("\" is invalid or already taken.")
|
||||
}
|
||||
onHandleLoginCompleted: {
|
||||
console.log("Login Succeeded")
|
||||
|
||||
bodyLoader.setSource("WelcomeBody.qml", { "welcomeBack" : false })
|
||||
bodyLoader.item.width = root.pane.width
|
||||
bodyLoader.item.height = root.pane.height
|
||||
}
|
||||
onHandleLoginFailed: {
|
||||
console.log("Login Failed")
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onPressed: {
|
||||
if (!visible) {
|
||||
return
|
||||
}
|
||||
|
||||
switch (event.key) {
|
||||
case Qt.Key_Enter:
|
||||
case Qt.Key_Return:
|
||||
event.accepted = true
|
||||
usernameCollisionBody.create()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
90
interface/resources/qml/LoginDialog/WelcomeBody.qml
Normal file
90
interface/resources/qml/LoginDialog/WelcomeBody.qml
Normal file
|
@ -0,0 +1,90 @@
|
|||
//
|
||||
// WelcomeBody.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import Hifi 1.0
|
||||
import QtQuick 2.4
|
||||
|
||||
import "../controls-uit"
|
||||
import "../styles-uit"
|
||||
|
||||
Item {
|
||||
id: welcomeBody
|
||||
clip: true
|
||||
width: pane.width
|
||||
height: pane.height
|
||||
|
||||
property bool welcomeBack: false
|
||||
|
||||
function setTitle() {
|
||||
root.title = (welcomeBack ? qsTr("Welcome back <b>") : qsTr("Welcome <b>")) + Account.username + qsTr("</b>!")
|
||||
root.iconText = ""
|
||||
d.resize();
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
readonly property int minWidth: 480
|
||||
readonly property int maxWidth: 1280
|
||||
readonly property int minHeight: 120
|
||||
readonly property int maxHeight: 720
|
||||
|
||||
function resize() {
|
||||
var targetWidth = Math.max(titleWidth, mainTextContainer.contentWidth)
|
||||
var targetHeight = mainTextContainer.height + 3 * hifi.dimensions.contentSpacing.y + buttons.height
|
||||
|
||||
root.width = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth))
|
||||
root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight))
|
||||
}
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
id: mainTextContainer
|
||||
anchors {
|
||||
top: parent.top
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
margins: 0
|
||||
topMargin: hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
|
||||
text: qsTr("You are now signed into High Fidelity")
|
||||
wrapMode: Text.WordWrap
|
||||
color: hifi.colors.baseGrayHighlight
|
||||
lineHeight: 2
|
||||
lineHeightMode: Text.ProportionalHeight
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
Row {
|
||||
id: buttons
|
||||
anchors {
|
||||
top: mainTextContainer.bottom
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
margins: 0
|
||||
topMargin: 2 * hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
spacing: hifi.dimensions.contentSpacing.x
|
||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||
|
||||
Button {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
text: qsTr("Close");
|
||||
|
||||
onClicked: root.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: welcomeBody.setTitle()
|
||||
|
||||
Connections {
|
||||
target: Account
|
||||
onUsernameChanged: welcomeBody.setTitle()
|
||||
}
|
||||
}
|
20
interface/resources/qml/controls-uit/HorizontalRule.qml
Normal file
20
interface/resources/qml/controls-uit/HorizontalRule.qml
Normal file
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// HorizontalRule.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
|
||||
Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 1
|
||||
color: hifi.colors.lightGray
|
||||
}
|
21
interface/resources/qml/controls-uit/HorizontalSpacer.qml
Normal file
21
interface/resources/qml/controls-uit/HorizontalSpacer.qml
Normal file
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// HorizontalSpacer.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
|
||||
import "../styles-uit"
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property alias size: root.width
|
||||
|
||||
width: hifi.dimensions.controlInterlineHeight
|
||||
height: 1 // Must be non-zero
|
||||
}
|
|
@ -13,6 +13,9 @@ import QtQuick 2.5
|
|||
import "../styles-uit"
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property alias size: root.height
|
||||
|
||||
width: 1 // Must be non-zero
|
||||
height: hifi.dimensions.controlInterlineHeight
|
||||
}
|
||||
|
|
|
@ -21,8 +21,6 @@ import "messageDialog"
|
|||
ModalWindow {
|
||||
id: root
|
||||
HifiConstants { id: hifi }
|
||||
implicitWidth: 640
|
||||
implicitHeight: 320
|
||||
destroyOnCloseButton: true
|
||||
destroyOnHidden: true
|
||||
visible: true
|
||||
|
@ -70,7 +68,7 @@ ModalWindow {
|
|||
QtObject {
|
||||
id: d
|
||||
readonly property int minWidth: 480
|
||||
readonly property int maxWdith: 1280
|
||||
readonly property int maxWidth: 1280
|
||||
readonly property int minHeight: 120
|
||||
readonly property int maxHeight: 720
|
||||
|
||||
|
@ -80,7 +78,7 @@ ModalWindow {
|
|||
+ (informativeTextContainer.text != "" ? informativeTextContainer.contentHeight + 3 * hifi.dimensions.contentSpacing.y : 0)
|
||||
+ buttons.height
|
||||
+ (content.state === "expanded" ? details.implicitHeight + hifi.dimensions.contentSpacing.y : 0)
|
||||
root.width = (targetWidth < d.minWidth) ? d.minWidth : ((targetWidth > d.maxWdith) ? d.maxWidth : targetWidth)
|
||||
root.width = (targetWidth < d.minWidth) ? d.minWidth : ((targetWidth > d.maxWidth) ? d.maxWidth : targetWidth)
|
||||
root.height = (targetHeight < d.minHeight) ? d.minHeight: ((targetHeight > d.maxHeight) ? d.maxHeight : targetHeight)
|
||||
}
|
||||
}
|
||||
|
|
18
interface/resources/qml/styles-uit/ButtonLabel.qml
Normal file
18
interface/resources/qml/styles-uit/ButtonLabel.qml
Normal file
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// ButtonLabel.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import "."
|
||||
|
||||
RalewayBold {
|
||||
font.pixelSize: hifi.fontSizes.buttonLabel
|
||||
}
|
20
interface/resources/qml/styles-uit/IconButton.qml
Normal file
20
interface/resources/qml/styles-uit/IconButton.qml
Normal file
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// IconButton.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import "."
|
||||
|
||||
RalewayRegular {
|
||||
font.pixelSize: hifi.fontSizes.iconButton
|
||||
font.capitalization: Font.AllUppercase
|
||||
font.letterSpacing: 1.5
|
||||
}
|
18
interface/resources/qml/styles-uit/InputLabel.qml
Normal file
18
interface/resources/qml/styles-uit/InputLabel.qml
Normal file
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// InputLabel.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import "."
|
||||
|
||||
RalewaySemiBold {
|
||||
font.pixelSize: hifi.fontSizes.inputLabel
|
||||
}
|
18
interface/resources/qml/styles-uit/ListItem.qml
Normal file
18
interface/resources/qml/styles-uit/ListItem.qml
Normal file
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// ListItem.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import "."
|
||||
|
||||
RalewayRegular {
|
||||
font.pixelSize: hifi.fontSizes.listItem
|
||||
}
|
18
interface/resources/qml/styles-uit/Logs.qml
Normal file
18
interface/resources/qml/styles-uit/Logs.qml
Normal file
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// Logs.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import "."
|
||||
|
||||
AnonymousProRegular {
|
||||
font.pixelSize: hifi.fontSizes.logs
|
||||
}
|
19
interface/resources/qml/styles-uit/MenuItem.qml
Normal file
19
interface/resources/qml/styles-uit/MenuItem.qml
Normal file
|
@ -0,0 +1,19 @@
|
|||
//
|
||||
// MenuItem.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import "."
|
||||
|
||||
RalewaySemiBold {
|
||||
lineHeight: 2
|
||||
font.pixelSize: hifi.fontSizes.menuItem
|
||||
}
|
18
interface/resources/qml/styles-uit/OverlayTitle.qml
Normal file
18
interface/resources/qml/styles-uit/OverlayTitle.qml
Normal file
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// OverlayTitle.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import "."
|
||||
|
||||
RalewayRegular {
|
||||
font.pixelSize: hifi.fontSizes.overlayTitle
|
||||
}
|
19
interface/resources/qml/styles-uit/SectionName.qml
Normal file
19
interface/resources/qml/styles-uit/SectionName.qml
Normal file
|
@ -0,0 +1,19 @@
|
|||
//
|
||||
// SectionName.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import "."
|
||||
|
||||
RalewayRegular {
|
||||
font.pixelSize: hifi.fontSizes.sectionName
|
||||
font.capitalization: Font.AllUppercase
|
||||
}
|
18
interface/resources/qml/styles-uit/ShortcutText.qml
Normal file
18
interface/resources/qml/styles-uit/ShortcutText.qml
Normal file
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// ShortcutText.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import "."
|
||||
|
||||
RalewayLight {
|
||||
font.pixelSize: hifi.fontSizes.shortcutText
|
||||
}
|
19
interface/resources/qml/styles-uit/TabName.qml
Normal file
19
interface/resources/qml/styles-uit/TabName.qml
Normal file
|
@ -0,0 +1,19 @@
|
|||
//
|
||||
// TabName.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import "."
|
||||
|
||||
RalewayRegular {
|
||||
font.pixelSize: hifi.fontSizes.tabName
|
||||
font.capitalization: Font.AllUppercase
|
||||
}
|
18
interface/resources/qml/styles-uit/TextFieldInput.qml
Normal file
18
interface/resources/qml/styles-uit/TextFieldInput.qml
Normal file
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// TextFieldInput.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import "."
|
||||
|
||||
FiraSansSemiBold {
|
||||
font.pixelSize: hifi.fontSizes.textFieldInput
|
||||
}
|
|
@ -86,15 +86,16 @@
|
|||
#include <PhysicsHelpers.h>
|
||||
#include <plugins/PluginManager.h>
|
||||
#include <plugins/CodecPlugin.h>
|
||||
#include <RecordingScriptingInterface.h>
|
||||
#include <RenderableWebEntityItem.h>
|
||||
#include <RenderShadowTask.h>
|
||||
#include <RenderDeferredTask.h>
|
||||
#include <ResourceCache.h>
|
||||
#include <SceneScriptingInterface.h>
|
||||
#include <RecordingScriptingInterface.h>
|
||||
#include <ScriptEngines.h>
|
||||
#include <ScriptCache.h>
|
||||
#include <SoundCache.h>
|
||||
#include <ScriptEngines.h>
|
||||
#include <steamworks-wrapper/SteamClient.h>
|
||||
#include <Tooltip.h>
|
||||
#include <udt/PacketHeaders.h>
|
||||
#include <UserActivityLogger.h>
|
||||
|
@ -1631,6 +1632,8 @@ void Application::initializeUi() {
|
|||
rootContext->setContextProperty("Reticle", getApplicationCompositor().getReticleInterface());
|
||||
|
||||
rootContext->setContextProperty("ApplicationCompositor", &getApplicationCompositor());
|
||||
|
||||
rootContext->setContextProperty("Steam", new SteamScriptingInterface(engine));
|
||||
|
||||
|
||||
_glWidget->installEventFilter(offscreenUi.data());
|
||||
|
@ -2943,6 +2946,8 @@ void Application::idle(float nsecsElapsed) {
|
|||
|
||||
PROFILE_RANGE(__FUNCTION__);
|
||||
|
||||
SteamClient::runCallbacks();
|
||||
|
||||
float secondsSinceLastUpdate = nsecsElapsed / NSECS_PER_MSEC / MSECS_PER_SECOND;
|
||||
|
||||
// If the offscreen Ui has something active that is NOT the root, then assume it has keyboard focus.
|
||||
|
@ -3251,6 +3256,14 @@ void Application::init() {
|
|||
addressLookupString = arguments().value(urlIndex + 1);
|
||||
}
|
||||
|
||||
// when +connect_lobby in command line, join steam lobby
|
||||
const QString STEAM_LOBBY_COMMAND_LINE_KEY = "+connect_lobby";
|
||||
int lobbyIndex = arguments().indexOf(STEAM_LOBBY_COMMAND_LINE_KEY);
|
||||
if (lobbyIndex != -1) {
|
||||
QString lobbyId = arguments().value(lobbyIndex + 1);
|
||||
SteamClient::joinLobby(lobbyId);
|
||||
}
|
||||
|
||||
Setting::Handle<bool> firstRun { Settings::firstRun, true };
|
||||
if (addressLookupString.isEmpty() && firstRun.get()) {
|
||||
qDebug() << "First run and no URL passed... attempting to go to Home or Entry...";
|
||||
|
@ -4837,6 +4850,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
|
|||
|
||||
scriptEngine->registerGlobalObject("UserActivityLogger", DependencyManager::get<UserActivityLoggerScriptingInterface>().data());
|
||||
scriptEngine->registerGlobalObject("Users", DependencyManager::get<UsersScriptingInterface>().data());
|
||||
|
||||
scriptEngine->registerGlobalObject("Steam", new SteamScriptingInterface(scriptEngine));
|
||||
}
|
||||
|
||||
bool Application::canAcceptURL(const QString& urlString) const {
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <AddressManager.h>
|
||||
#include <DomainHandler.h>
|
||||
#include <NodeList.h>
|
||||
#include <steamworks-wrapper/SteamClient.h>
|
||||
#include <UserActivityLogger.h>
|
||||
#include <UUID.h>
|
||||
|
||||
|
@ -36,11 +37,11 @@ const QString SESSION_ID_KEY = "session_id";
|
|||
|
||||
void DiscoverabilityManager::updateLocation() {
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
|
||||
if (_mode.get() != Discoverability::None && accountManager->isLoggedIn()) {
|
||||
auto addressManager = DependencyManager::get<AddressManager>();
|
||||
DomainHandler& domainHandler = DependencyManager::get<NodeList>()->getDomainHandler();
|
||||
auto addressManager = DependencyManager::get<AddressManager>();
|
||||
auto& domainHandler = DependencyManager::get<NodeList>()->getDomainHandler();
|
||||
|
||||
|
||||
if (_mode.get() != Discoverability::None && accountManager->isLoggedIn()) {
|
||||
// construct a QJsonObject given the user's current address information
|
||||
QJsonObject rootObject;
|
||||
|
||||
|
@ -48,8 +49,6 @@ void DiscoverabilityManager::updateLocation() {
|
|||
|
||||
QString pathString = addressManager->currentPath();
|
||||
|
||||
const QString LOCATION_KEY_IN_ROOT = "location";
|
||||
|
||||
const QString PATH_KEY_IN_LOCATION = "path";
|
||||
locationObject.insert(PATH_KEY_IN_LOCATION, pathString);
|
||||
|
||||
|
@ -90,6 +89,7 @@ void DiscoverabilityManager::updateLocation() {
|
|||
// we have a changed location, send it now
|
||||
_lastLocationObject = locationObject;
|
||||
|
||||
const QString LOCATION_KEY_IN_ROOT = "location";
|
||||
rootObject.insert(LOCATION_KEY_IN_ROOT, locationObject);
|
||||
|
||||
apiPath = API_USER_LOCATION_PATH;
|
||||
|
@ -109,6 +109,9 @@ void DiscoverabilityManager::updateLocation() {
|
|||
accountManager->sendRequest(API_USER_HEARTBEAT_PATH, AccountManagerAuth::Optional,
|
||||
QNetworkAccessManager::PutOperation, callbackParameters);
|
||||
}
|
||||
|
||||
// Update Steam
|
||||
SteamClient::updateLocation(domainHandler.getHostname(), addressManager->currentFacingAddress());
|
||||
}
|
||||
|
||||
void DiscoverabilityManager::handleHeartbeatResponse(QNetworkReply& requestReply) {
|
||||
|
|
|
@ -122,11 +122,13 @@ MyAvatar::MyAvatar(RigPointer rig) :
|
|||
_driveKeys[i] = 0.0f;
|
||||
}
|
||||
|
||||
|
||||
// Necessary to select the correct slot
|
||||
using SlotType = void(MyAvatar::*)(const glm::vec3&, bool, const glm::quat&, bool);
|
||||
|
||||
// connect to AddressManager signal for location jumps
|
||||
connect(DependencyManager::get<AddressManager>().data(), &AddressManager::locationChangeRequired,
|
||||
[=](const glm::vec3& newPosition, bool hasOrientation, const glm::quat& newOrientation, bool shouldFaceLocation){
|
||||
goToLocation(newPosition, hasOrientation, newOrientation, shouldFaceLocation);
|
||||
});
|
||||
connect(DependencyManager::get<AddressManager>().data(), &AddressManager::locationChangeRequired,
|
||||
this, static_cast<SlotType>(&MyAvatar::goToLocation));
|
||||
|
||||
_characterController.setEnabled(true);
|
||||
|
||||
|
@ -1859,7 +1861,7 @@ void MyAvatar::goToLocation(const glm::vec3& newPosition,
|
|||
glm::quat quatOrientation = cancelOutRollAndPitch(newOrientation);
|
||||
|
||||
if (shouldFaceLocation) {
|
||||
quatOrientation = newOrientation * glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
quatOrientation = newOrientation * glm::angleAxis(PI, Vectors::UP);
|
||||
|
||||
// move the user a couple units away
|
||||
const float DISTANCE_TO_USER = 2.0f;
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include <QCommandLineParser>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
|
@ -20,12 +22,13 @@
|
|||
#include <gl/OpenGLVersionChecker.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include <steamworks-wrapper/SteamClient.h>
|
||||
|
||||
#include "AddressManager.h"
|
||||
#include "Application.h"
|
||||
#include "InterfaceLogging.h"
|
||||
#include "UserActivityLogger.h"
|
||||
#include "MainWindow.h"
|
||||
#include <thread>
|
||||
|
||||
#ifdef HAS_BUGSPLAT
|
||||
#include <BuildInfo.h>
|
||||
|
@ -137,6 +140,8 @@ int main(int argc, const char* argv[]) {
|
|||
// or in the main window ctor, before GL startup.
|
||||
Application::initPlugins(arguments);
|
||||
|
||||
SteamClient::init();
|
||||
|
||||
int exitCode;
|
||||
{
|
||||
QSettings::setDefaultFormat(QSettings::IniFormat);
|
||||
|
@ -202,6 +207,8 @@ int main(int argc, const char* argv[]) {
|
|||
|
||||
Application::shutdownPlugins();
|
||||
|
||||
SteamClient::shutdown();
|
||||
|
||||
qCDebug(interfaceapp, "Normal exit.");
|
||||
#if !defined(DEBUG) && !defined(Q_OS_LINUX)
|
||||
// HACK: exit immediately (don't handle shutdown callbacks) for Release build
|
||||
|
|
|
@ -15,6 +15,9 @@
|
|||
|
||||
AccountScriptingInterface* AccountScriptingInterface::getInstance() {
|
||||
static AccountScriptingInterface sharedInstance;
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
QObject::connect(accountManager.data(), &AccountManager::profileChanged,
|
||||
&sharedInstance, &AccountScriptingInterface::usernameChanged);
|
||||
return &sharedInstance;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,11 @@
|
|||
class AccountScriptingInterface : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString username READ getUsername NOTIFY usernameChanged)
|
||||
|
||||
signals:
|
||||
void usernameChanged();
|
||||
|
||||
public slots:
|
||||
static AccountScriptingInterface* getInstance();
|
||||
QString getUsername();
|
||||
|
|
|
@ -12,8 +12,11 @@
|
|||
#include "LoginDialog.h"
|
||||
|
||||
#include <QDesktopServices>
|
||||
#include <QJsonDocument>
|
||||
#include <QNetworkReply>
|
||||
|
||||
#include <NetworkingConstants.h>
|
||||
#include <steamworks-wrapper/SteamClient.h>
|
||||
|
||||
#include "AccountManager.h"
|
||||
#include "DependencyManager.h"
|
||||
|
@ -21,9 +24,7 @@
|
|||
|
||||
HIFI_QML_DEF(LoginDialog)
|
||||
|
||||
LoginDialog::LoginDialog(QQuickItem *parent) : OffscreenQmlDialog(parent),
|
||||
_rootUrl(NetworkingConstants::METAVERSE_SERVER_URL.toString())
|
||||
{
|
||||
LoginDialog::LoginDialog(QQuickItem *parent) : OffscreenQmlDialog(parent) {
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
connect(accountManager.data(), &AccountManager::loginComplete,
|
||||
this, &LoginDialog::handleLoginCompleted);
|
||||
|
@ -53,36 +54,102 @@ void LoginDialog::toggleAction() {
|
|||
}
|
||||
}
|
||||
|
||||
void LoginDialog::handleLoginCompleted(const QUrl&) {
|
||||
hide();
|
||||
bool LoginDialog::isSteamRunning() const {
|
||||
return SteamClient::isRunning();
|
||||
}
|
||||
|
||||
void LoginDialog::handleLoginFailed() {
|
||||
setStatusText("Invalid username or password");
|
||||
}
|
||||
|
||||
void LoginDialog::setStatusText(const QString& statusText) {
|
||||
if (statusText != _statusText) {
|
||||
_statusText = statusText;
|
||||
emit statusTextChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QString LoginDialog::statusText() const {
|
||||
return _statusText;
|
||||
}
|
||||
|
||||
QString LoginDialog::rootUrl() const {
|
||||
return _rootUrl;
|
||||
}
|
||||
|
||||
void LoginDialog::login(const QString& username, const QString& password) {
|
||||
void LoginDialog::login(const QString& username, const QString& password) const {
|
||||
qDebug() << "Attempting to login " << username;
|
||||
setStatusText("Logging in...");
|
||||
DependencyManager::get<AccountManager>()->requestAccessToken(username, password);
|
||||
}
|
||||
|
||||
void LoginDialog::openUrl(const QString& url) {
|
||||
qDebug() << url;
|
||||
QDesktopServices::openUrl(url);
|
||||
void LoginDialog::loginThroughSteam() {
|
||||
qDebug() << "Attempting to login through Steam";
|
||||
SteamClient::requestTicket([this](Ticket ticket) {
|
||||
if (ticket.isNull()) {
|
||||
emit handleLoginFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
DependencyManager::get<AccountManager>()->requestAccessTokenWithSteam(ticket);
|
||||
});
|
||||
}
|
||||
|
||||
void LoginDialog::linkSteam() {
|
||||
qDebug() << "Attempting to link Steam account";
|
||||
SteamClient::requestTicket([this](Ticket ticket) {
|
||||
if (ticket.isNull()) {
|
||||
emit handleLoginFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
JSONCallbackParameters callbackParams;
|
||||
callbackParams.jsonCallbackReceiver = this;
|
||||
callbackParams.jsonCallbackMethod = "linkCompleted";
|
||||
callbackParams.errorCallbackReceiver = this;
|
||||
callbackParams.errorCallbackMethod = "linkFailed";
|
||||
|
||||
const QString LINK_STEAM_PATH = "api/v1/user/steam/link";
|
||||
|
||||
QJsonObject payload;
|
||||
payload.insert("steam_auth_ticket", QJsonValue::fromVariant(QVariant(ticket)));
|
||||
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
accountManager->sendRequest(LINK_STEAM_PATH, AccountManagerAuth::Required,
|
||||
QNetworkAccessManager::PostOperation, callbackParams,
|
||||
QJsonDocument(payload).toJson());
|
||||
});
|
||||
}
|
||||
|
||||
void LoginDialog::createAccountFromStream(QString username) {
|
||||
qDebug() << "Attempting to create account from Steam info";
|
||||
SteamClient::requestTicket([this, username](Ticket ticket) {
|
||||
if (ticket.isNull()) {
|
||||
emit handleLoginFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
JSONCallbackParameters callbackParams;
|
||||
callbackParams.jsonCallbackReceiver = this;
|
||||
callbackParams.jsonCallbackMethod = "createCompleted";
|
||||
callbackParams.errorCallbackReceiver = this;
|
||||
callbackParams.errorCallbackMethod = "createFailed";
|
||||
|
||||
const QString CREATE_ACCOUNT_FROM_STEAM_PATH = "api/v1/user/steam/create";
|
||||
|
||||
QJsonObject payload;
|
||||
payload.insert("steam_auth_ticket", QJsonValue::fromVariant(QVariant(ticket)));
|
||||
if (!username.isEmpty()) {
|
||||
payload.insert("username", QJsonValue::fromVariant(QVariant(username)));
|
||||
}
|
||||
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
accountManager->sendRequest(CREATE_ACCOUNT_FROM_STEAM_PATH, AccountManagerAuth::None,
|
||||
QNetworkAccessManager::PostOperation, callbackParams,
|
||||
QJsonDocument(payload).toJson());
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
void LoginDialog::openUrl(const QString& url) const {
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
auto browser = offscreenUi->load("Browser.qml");
|
||||
browser->setProperty("url", url);
|
||||
}
|
||||
|
||||
void LoginDialog::linkCompleted(QNetworkReply& reply) {
|
||||
emit handleLinkCompleted();
|
||||
}
|
||||
|
||||
void LoginDialog::linkFailed(QNetworkReply& reply) {
|
||||
emit handleLinkFailed(reply.errorString());
|
||||
}
|
||||
|
||||
void LoginDialog::createCompleted(QNetworkReply& reply) {
|
||||
emit handleCreateCompleted();
|
||||
}
|
||||
|
||||
void LoginDialog::createFailed(QNetworkReply& reply) {
|
||||
emit handleCreateFailed(reply.errorString());
|
||||
}
|
||||
|
||||
|
|
|
@ -16,35 +16,44 @@
|
|||
|
||||
#include <OffscreenQmlDialog.h>
|
||||
|
||||
class QNetworkReply;
|
||||
|
||||
class LoginDialog : public OffscreenQmlDialog {
|
||||
Q_OBJECT
|
||||
HIFI_QML_DECL
|
||||
|
||||
Q_PROPERTY(QString statusText READ statusText WRITE setStatusText NOTIFY statusTextChanged)
|
||||
Q_PROPERTY(QString rootUrl READ rootUrl)
|
||||
|
||||
public:
|
||||
static void toggleAction();
|
||||
|
||||
LoginDialog(QQuickItem* parent = nullptr);
|
||||
|
||||
void setStatusText(const QString& statusText);
|
||||
QString statusText() const;
|
||||
|
||||
QString rootUrl() const;
|
||||
|
||||
signals:
|
||||
void statusTextChanged();
|
||||
|
||||
protected:
|
||||
void handleLoginCompleted(const QUrl& authURL);
|
||||
void handleLoginCompleted();
|
||||
void handleLoginFailed();
|
||||
|
||||
Q_INVOKABLE void login(const QString& username, const QString& password);
|
||||
Q_INVOKABLE void openUrl(const QString& url);
|
||||
private:
|
||||
QString _statusText;
|
||||
const QString _rootUrl;
|
||||
void handleLinkCompleted();
|
||||
void handleLinkFailed(QString error);
|
||||
|
||||
void handleCreateCompleted();
|
||||
void handleCreateFailed(QString error);
|
||||
|
||||
public slots:
|
||||
void linkCompleted(QNetworkReply& reply);
|
||||
void linkFailed(QNetworkReply& reply);
|
||||
|
||||
void createCompleted(QNetworkReply& reply);
|
||||
void createFailed(QNetworkReply& reply);
|
||||
|
||||
protected slots:
|
||||
Q_INVOKABLE bool isSteamRunning() const;
|
||||
|
||||
Q_INVOKABLE void login(const QString& username, const QString& password) const;
|
||||
Q_INVOKABLE void loginThroughSteam();
|
||||
Q_INVOKABLE void linkSteam();
|
||||
Q_INVOKABLE void createAccountFromStream(QString username = QString());
|
||||
|
||||
Q_INVOKABLE void openUrl(const QString& url) const;
|
||||
|
||||
};
|
||||
|
||||
#endif // hifi_LoginDialog_h
|
||||
|
|
|
@ -505,6 +505,29 @@ void AccountManager::requestAccessToken(const QString& login, const QString& pas
|
|||
connect(requestReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(requestAccessTokenError(QNetworkReply::NetworkError)));
|
||||
}
|
||||
|
||||
void AccountManager::requestAccessTokenWithSteam(QByteArray authSessionTicket) {
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
|
||||
QNetworkRequest request;
|
||||
request.setHeader(QNetworkRequest::UserAgentHeader, _userAgentGetter());
|
||||
|
||||
QUrl grantURL = _authURL;
|
||||
grantURL.setPath("/oauth/token");
|
||||
|
||||
const QString ACCOUNT_MANAGER_REQUESTED_SCOPE = "owner";
|
||||
|
||||
QByteArray postData;
|
||||
postData.append("grant_type=password&");
|
||||
postData.append("steam_auth_ticket=" + QUrl::toPercentEncoding(authSessionTicket) + "&");
|
||||
postData.append("scope=" + ACCOUNT_MANAGER_REQUESTED_SCOPE);
|
||||
|
||||
request.setUrl(grantURL);
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||
|
||||
QNetworkReply* requestReply = networkAccessManager.post(request, postData);
|
||||
connect(requestReply, &QNetworkReply::finished, this, &AccountManager::requestAccessTokenFinished);
|
||||
connect(requestReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(requestAccessTokenError(QNetworkReply::NetworkError)));
|
||||
}
|
||||
|
||||
void AccountManager::requestAccessTokenFinished() {
|
||||
QNetworkReply* requestReply = reinterpret_cast<QNetworkReply*>(sender());
|
||||
|
@ -545,6 +568,7 @@ void AccountManager::requestAccessTokenFinished() {
|
|||
void AccountManager::requestAccessTokenError(QNetworkReply::NetworkError error) {
|
||||
// TODO: error handling
|
||||
qCDebug(networking) << "AccountManager requestError - " << error;
|
||||
emit loginFailed();
|
||||
}
|
||||
|
||||
void AccountManager::requestProfile() {
|
||||
|
|
|
@ -96,6 +96,7 @@ public:
|
|||
|
||||
public slots:
|
||||
void requestAccessToken(const QString& login, const QString& password);
|
||||
void requestAccessTokenWithSteam(QByteArray authSessionTicket);
|
||||
|
||||
void requestAccessTokenFinished();
|
||||
void requestProfileFinished();
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <QStringList>
|
||||
|
||||
#include <GLMHelpers.h>
|
||||
#include <NumericalConstants.h>
|
||||
#include <SettingHandle.h>
|
||||
#include <UUID.h>
|
||||
|
||||
|
@ -46,7 +47,7 @@ bool AddressManager::isConnected() {
|
|||
return DependencyManager::get<NodeList>()->getDomainHandler().isConnected();
|
||||
}
|
||||
|
||||
const QUrl AddressManager::currentAddress() const {
|
||||
QUrl AddressManager::currentAddress() const {
|
||||
QUrl hifiURL;
|
||||
|
||||
hifiURL.setScheme(HIFI_URL_SCHEME);
|
||||
|
@ -61,6 +62,21 @@ const QUrl AddressManager::currentAddress() const {
|
|||
return hifiURL;
|
||||
}
|
||||
|
||||
QUrl AddressManager::currentFacingAddress() const {
|
||||
QUrl hifiURL;
|
||||
|
||||
hifiURL.setScheme(HIFI_URL_SCHEME);
|
||||
hifiURL.setHost(_host);
|
||||
|
||||
if (_port != 0 && _port != DEFAULT_DOMAIN_SERVER_PORT) {
|
||||
hifiURL.setPort(_port);
|
||||
}
|
||||
|
||||
hifiURL.setPath(currentFacingPath());
|
||||
|
||||
return hifiURL;
|
||||
}
|
||||
|
||||
void AddressManager::loadSettings(const QString& lookupString) {
|
||||
if (lookupString.isEmpty()) {
|
||||
handleUrl(currentAddressHandle.get().toString(), LookupTrigger::StartupFromSettings);
|
||||
|
@ -97,7 +113,7 @@ void AddressManager::storeCurrentAddress() {
|
|||
currentAddressHandle.set(currentAddress());
|
||||
}
|
||||
|
||||
const QString AddressManager::currentPath(bool withOrientation) const {
|
||||
QString AddressManager::currentPath(bool withOrientation) const {
|
||||
|
||||
if (_positionGetter) {
|
||||
QString pathString = "/" + createByteArray(_positionGetter());
|
||||
|
@ -121,6 +137,25 @@ const QString AddressManager::currentPath(bool withOrientation) const {
|
|||
}
|
||||
}
|
||||
|
||||
QString AddressManager::currentFacingPath() const {
|
||||
if (_positionGetter && _orientationGetter) {
|
||||
auto position = _positionGetter();
|
||||
auto orientation = _orientationGetter();
|
||||
|
||||
// move the user a couple units away
|
||||
const float DISTANCE_TO_USER = 2.0f;
|
||||
position += orientation * Vectors::FRONT * DISTANCE_TO_USER;
|
||||
|
||||
// rotate the user by 180 degrees
|
||||
orientation = orientation * glm::angleAxis(PI, Vectors::UP);
|
||||
|
||||
return "/" + createByteArray(position) + "/" + createByteArray(orientation);
|
||||
} else {
|
||||
qCDebug(networking) << "Cannot create address path without a getter for position/orientation.";
|
||||
return QString();
|
||||
}
|
||||
}
|
||||
|
||||
const JSONCallbackParameters& AddressManager::apiCallbackParameters() {
|
||||
static bool hasSetupParameters = false;
|
||||
static JSONCallbackParameters callbackParams;
|
||||
|
|
|
@ -57,8 +57,10 @@ public:
|
|||
bool isConnected();
|
||||
const QString& getProtocol() { return HIFI_URL_SCHEME; };
|
||||
|
||||
const QUrl currentAddress() const;
|
||||
const QString currentPath(bool withOrientation = true) const;
|
||||
QUrl currentAddress() const;
|
||||
QUrl currentFacingAddress() const;
|
||||
QString currentPath(bool withOrientation = true) const;
|
||||
QString currentFacingPath() const;
|
||||
|
||||
const QUuid& getRootPlaceID() const { return _rootPlaceID; }
|
||||
const QString& getPlaceName() const { return _placeName; }
|
||||
|
|
|
@ -11,9 +11,303 @@
|
|||
|
||||
#include "SteamClient.h"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QMimeData>
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QUrl>
|
||||
#include <QtGui/qevent.h>
|
||||
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Woverloaded-virtual"
|
||||
#endif
|
||||
|
||||
#include <steam/steam_api.h>
|
||||
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
|
||||
static const Ticket INVALID_TICKET = Ticket();
|
||||
|
||||
class SteamTicketRequests {
|
||||
public:
|
||||
SteamTicketRequests();
|
||||
~SteamTicketRequests();
|
||||
|
||||
HAuthTicket startRequest(TicketRequestCallback callback);
|
||||
void stopRequest(HAuthTicket authTicket);
|
||||
void stopAll();
|
||||
|
||||
STEAM_CALLBACK(SteamTicketRequests, onGetAuthSessionTicketResponse,
|
||||
GetAuthSessionTicketResponse_t, _getAuthSessionTicketResponse);
|
||||
|
||||
private:
|
||||
struct PendingTicket {
|
||||
HAuthTicket authTicket;
|
||||
Ticket ticket;
|
||||
TicketRequestCallback callback;
|
||||
};
|
||||
|
||||
std::vector<PendingTicket> _pendingTickets;
|
||||
};
|
||||
|
||||
SteamTicketRequests::SteamTicketRequests() :
|
||||
_getAuthSessionTicketResponse(this, &SteamTicketRequests::onGetAuthSessionTicketResponse)
|
||||
{
|
||||
}
|
||||
|
||||
SteamTicketRequests::~SteamTicketRequests() {
|
||||
stopAll();
|
||||
}
|
||||
|
||||
HAuthTicket SteamTicketRequests::startRequest(TicketRequestCallback callback) {
|
||||
static const uint32 MAX_TICKET_SIZE { 1024 };
|
||||
uint32 ticketSize { 0 };
|
||||
char ticket[MAX_TICKET_SIZE];
|
||||
|
||||
auto authTicket = SteamUser()->GetAuthSessionTicket(ticket, MAX_TICKET_SIZE, &ticketSize);
|
||||
qDebug() << "Got Steam auth session ticket:" << authTicket;
|
||||
|
||||
if (authTicket == k_HAuthTicketInvalid) {
|
||||
qWarning() << "Auth session ticket is invalid.";
|
||||
callback(INVALID_TICKET);
|
||||
} else {
|
||||
PendingTicket pendingTicket{ authTicket, QByteArray(ticket, ticketSize).toHex(), callback };
|
||||
_pendingTickets.push_back(pendingTicket);
|
||||
}
|
||||
|
||||
return authTicket;
|
||||
}
|
||||
|
||||
void SteamTicketRequests::stopRequest(HAuthTicket authTicket) {
|
||||
auto it = std::find_if(_pendingTickets.begin(), _pendingTickets.end(), [&authTicket](const PendingTicket& pendingTicket) {
|
||||
return pendingTicket.authTicket == authTicket;
|
||||
});
|
||||
|
||||
if (it != _pendingTickets.end()) {
|
||||
SteamUser()->CancelAuthTicket(it->authTicket);
|
||||
it->callback(INVALID_TICKET);
|
||||
_pendingTickets.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void SteamTicketRequests::stopAll() {
|
||||
auto steamUser = SteamUser();
|
||||
if (steamUser) {
|
||||
for (const auto& pendingTicket : _pendingTickets) {
|
||||
steamUser->CancelAuthTicket(pendingTicket.authTicket);
|
||||
pendingTicket.callback(INVALID_TICKET);
|
||||
}
|
||||
}
|
||||
_pendingTickets.clear();
|
||||
}
|
||||
|
||||
void SteamTicketRequests::onGetAuthSessionTicketResponse(GetAuthSessionTicketResponse_t* pCallback) {
|
||||
auto authTicket = pCallback->m_hAuthTicket;
|
||||
|
||||
auto it = std::find_if(_pendingTickets.begin(), _pendingTickets.end(), [&authTicket](const PendingTicket& pendingTicket) {
|
||||
return pendingTicket.authTicket == authTicket;
|
||||
});
|
||||
|
||||
|
||||
if (it != _pendingTickets.end()) {
|
||||
|
||||
if (pCallback->m_eResult == k_EResultOK) {
|
||||
qDebug() << "Got steam callback, auth session ticket is valid. Send it." << authTicket;
|
||||
it->callback(it->ticket);
|
||||
} else {
|
||||
qWarning() << "Steam auth session ticket callback encountered an error:" << pCallback->m_eResult;
|
||||
it->callback(INVALID_TICKET);
|
||||
}
|
||||
|
||||
_pendingTickets.erase(it);
|
||||
} else {
|
||||
qWarning() << "Could not find steam auth session ticket in list of pending tickets:" << authTicket;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const QString CONNECT_PREFIX = "--url \"";
|
||||
const QString CONNECT_SUFFIX = "\"";
|
||||
|
||||
class SteamCallbackManager {
|
||||
public:
|
||||
SteamCallbackManager();
|
||||
|
||||
STEAM_CALLBACK(SteamCallbackManager, onGameRichPresenceJoinRequested,
|
||||
GameRichPresenceJoinRequested_t, _gameRichPresenceJoinRequestedResponse);
|
||||
|
||||
STEAM_CALLBACK(SteamCallbackManager, onLobbyCreated,
|
||||
LobbyCreated_t, _lobbyCreatedResponse);
|
||||
|
||||
STEAM_CALLBACK(SteamCallbackManager, onGameLobbyJoinRequested,
|
||||
GameLobbyJoinRequested_t, _gameLobbyJoinRequestedResponse);
|
||||
|
||||
STEAM_CALLBACK(SteamCallbackManager, onLobbyEnter,
|
||||
LobbyEnter_t, _lobbyEnterResponse);
|
||||
|
||||
SteamTicketRequests& getTicketRequests() { return _steamTicketRequests; }
|
||||
|
||||
private:
|
||||
SteamTicketRequests _steamTicketRequests;
|
||||
};
|
||||
|
||||
SteamCallbackManager::SteamCallbackManager() :
|
||||
_gameRichPresenceJoinRequestedResponse(this, &SteamCallbackManager::onGameRichPresenceJoinRequested),
|
||||
_lobbyCreatedResponse(this, &SteamCallbackManager::onLobbyCreated),
|
||||
_gameLobbyJoinRequestedResponse(this, &SteamCallbackManager::onGameLobbyJoinRequested),
|
||||
_lobbyEnterResponse(this, &SteamCallbackManager::onLobbyEnter)
|
||||
{
|
||||
}
|
||||
|
||||
void parseUrlAndGo(QString url) {
|
||||
if (url.startsWith(CONNECT_PREFIX) && url.endsWith(CONNECT_SUFFIX)) {
|
||||
url.remove(0, CONNECT_PREFIX.size());
|
||||
url.remove(-CONNECT_SUFFIX.size(), CONNECT_SUFFIX.size());
|
||||
}
|
||||
|
||||
qDebug() << "Joining Steam Friend at:" << url;
|
||||
auto mimeData = new QMimeData();
|
||||
mimeData->setUrls(QList<QUrl>() << QUrl(url));
|
||||
auto event = new QDropEvent(QPointF(0, 0), Qt::MoveAction, mimeData, Qt::LeftButton, Qt::NoModifier);
|
||||
|
||||
QCoreApplication::postEvent(qApp, event);
|
||||
}
|
||||
|
||||
void SteamCallbackManager::onGameRichPresenceJoinRequested(GameRichPresenceJoinRequested_t* pCallback) {
|
||||
auto url = QString::fromLocal8Bit(pCallback->m_rgchConnect);
|
||||
|
||||
parseUrlAndGo(url);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SteamCallbackManager::onLobbyCreated(LobbyCreated_t* pCallback) {
|
||||
if (pCallback->m_eResult == k_EResultOK) {
|
||||
qDebug() << "Inviting steam friends" << pCallback->m_ulSteamIDLobby;
|
||||
|
||||
auto url = SteamFriends()->GetFriendRichPresence(SteamUser()->GetSteamID(), "connect");
|
||||
SteamMatchmaking()->SetLobbyData(pCallback->m_ulSteamIDLobby, "connect", url);
|
||||
SteamFriends()->ActivateGameOverlayInviteDialog(pCallback->m_ulSteamIDLobby);
|
||||
}
|
||||
}
|
||||
|
||||
void SteamCallbackManager::onGameLobbyJoinRequested(GameLobbyJoinRequested_t* pCallback) {
|
||||
qDebug() << "Joining Steam lobby" << pCallback->m_steamIDLobby.ConvertToUint64();
|
||||
SteamMatchmaking()->JoinLobby(pCallback->m_steamIDLobby);
|
||||
}
|
||||
|
||||
void SteamCallbackManager::onLobbyEnter(LobbyEnter_t* pCallback) {
|
||||
if (pCallback->m_EChatRoomEnterResponse != k_EChatRoomEnterResponseSuccess) {
|
||||
qWarning() << "An error occured while joing the Steam lobby:" << pCallback->m_EChatRoomEnterResponse;
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "Entered Steam lobby" << pCallback->m_ulSteamIDLobby;
|
||||
|
||||
if (SteamMatchmaking()->GetLobbyOwner(pCallback->m_ulSteamIDLobby) != SteamUser()->GetSteamID()) {
|
||||
auto url = SteamMatchmaking()->GetLobbyData(pCallback->m_ulSteamIDLobby, "connect");
|
||||
qDebug() << "Jumping to" << url;
|
||||
parseUrlAndGo(url);
|
||||
SteamMatchmaking()->LeaveLobby(pCallback->m_ulSteamIDLobby);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static std::atomic_bool initialized { false };
|
||||
static SteamCallbackManager steamCallbackManager;
|
||||
|
||||
|
||||
bool SteamClient::isRunning() {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
bool SteamClient::init() {
|
||||
if (SteamAPI_IsSteamRunning() && !initialized) {
|
||||
initialized = SteamAPI_Init();
|
||||
}
|
||||
return initialized;
|
||||
}
|
||||
|
||||
void SteamClient::shutdown() {
|
||||
if (initialized) {
|
||||
SteamAPI_Shutdown();
|
||||
}
|
||||
|
||||
steamCallbackManager.getTicketRequests().stopAll();
|
||||
}
|
||||
|
||||
void SteamClient::runCallbacks() {
|
||||
if (!initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto steamPipe = SteamAPI_GetHSteamPipe();
|
||||
if (!steamPipe) {
|
||||
qDebug() << "Could not get SteamPipe";
|
||||
return;
|
||||
}
|
||||
|
||||
Steam_RunCallbacks(steamPipe, false);
|
||||
}
|
||||
|
||||
void SteamClient::requestTicket(TicketRequestCallback callback) {
|
||||
if (!initialized) {
|
||||
if (SteamAPI_IsSteamRunning()) {
|
||||
init();
|
||||
} else {
|
||||
qWarning() << "Steam is not running";
|
||||
callback(INVALID_TICKET);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!initialized) {
|
||||
qDebug() << "Steam not initialized";
|
||||
return;
|
||||
}
|
||||
|
||||
steamCallbackManager.getTicketRequests().startRequest(callback);
|
||||
}
|
||||
|
||||
void SteamClient::updateLocation(QString status, QUrl locationUrl) {
|
||||
if (!initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto connectStr = locationUrl.isEmpty() ? "" : CONNECT_PREFIX + locationUrl.toString() + CONNECT_SUFFIX;
|
||||
|
||||
SteamFriends()->SetRichPresence("status", status.toLocal8Bit().data());
|
||||
SteamFriends()->SetRichPresence("connect", connectStr.toLocal8Bit().data());
|
||||
}
|
||||
|
||||
void SteamClient::openInviteOverlay() {
|
||||
if (!initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "Creating Steam lobby";
|
||||
static const int MAX_LOBBY_SIZE = 20;
|
||||
SteamMatchmaking()->CreateLobby(k_ELobbyTypePrivate, MAX_LOBBY_SIZE);
|
||||
}
|
||||
|
||||
|
||||
void SteamClient::joinLobby(QString lobbyIdStr) {
|
||||
if (!initialized) {
|
||||
if (SteamAPI_IsSteamRunning()) {
|
||||
init();
|
||||
} else {
|
||||
qWarning() << "Steam is not running";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
qDebug() << "Trying to join Steam lobby:" << lobbyIdStr;
|
||||
CSteamID lobbyId(lobbyIdStr.toULongLong());
|
||||
SteamMatchmaking()->JoinLobby(lobbyId);
|
||||
}
|
|
@ -13,8 +13,43 @@
|
|||
#ifndef hifi_SteamClient_h
|
||||
#define hifi_SteamClient_h
|
||||
|
||||
class SteamClient {
|
||||
#include <functional>
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QByteArray>
|
||||
|
||||
using Ticket = QByteArray;
|
||||
using TicketRequestCallback = std::function<void(Ticket)>;
|
||||
|
||||
class QUrl;
|
||||
|
||||
class SteamClient {
|
||||
public:
|
||||
static bool isRunning();
|
||||
|
||||
static bool init();
|
||||
static void shutdown();
|
||||
|
||||
static void runCallbacks();
|
||||
|
||||
static void requestTicket(TicketRequestCallback callback);
|
||||
static void updateLocation(QString status, QUrl locationUrl);
|
||||
static void openInviteOverlay();
|
||||
static void joinLobby(QString lobbyId);
|
||||
|
||||
};
|
||||
|
||||
class SteamScriptingInterface : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(bool isRunning READ isRunning)
|
||||
|
||||
public:
|
||||
SteamScriptingInterface(QObject* parent) : QObject(parent) {}
|
||||
|
||||
public slots:
|
||||
bool isRunning() const { return SteamClient::isRunning(); }
|
||||
void openInviteOverlay() const { SteamClient::openInviteOverlay(); }
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -161,7 +161,10 @@ static bool isBadPose(vr::HmdMatrix34_t* mat) {
|
|||
|
||||
bool OpenVrDisplayPlugin::beginFrameRender(uint32_t frameIndex) {
|
||||
handleOpenVrEvents();
|
||||
|
||||
if (openVrQuitRequested()) {
|
||||
QMetaObject::invokeMethod(qApp, "quit");
|
||||
return false;
|
||||
}
|
||||
double displayFrequency = _system->GetFloatTrackedDeviceProperty(vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_DisplayFrequency_Float);
|
||||
double frameDuration = 1.f / displayFrequency;
|
||||
double vsyncToPhotons = _system->GetFloatTrackedDeviceProperty(vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_SecondsFromVsyncToPhotons_Float);
|
||||
|
|
|
@ -34,6 +34,11 @@ using Lock = std::unique_lock<Mutex>;
|
|||
static int refCount { 0 };
|
||||
static Mutex mutex;
|
||||
static vr::IVRSystem* activeHmd { nullptr };
|
||||
static bool _openVrQuitRequested { false };
|
||||
|
||||
bool openVrQuitRequested() {
|
||||
return _openVrQuitRequested;
|
||||
}
|
||||
|
||||
static const uint32_t RELEASE_OPENVR_HMD_DELAY_MS = 5000;
|
||||
|
||||
|
@ -99,6 +104,7 @@ void releaseOpenVrSystem() {
|
|||
qCDebug(displayplugins) << "OpenVR: zero refcount, deallocate VR system";
|
||||
#endif
|
||||
vr::VR_Shutdown();
|
||||
_openVrQuitRequested = false;
|
||||
activeHmd = nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -257,8 +263,8 @@ void handleOpenVrEvents() {
|
|||
while (activeHmd->PollNextEvent(&event, sizeof(event))) {
|
||||
switch (event.eventType) {
|
||||
case vr::VREvent_Quit:
|
||||
_openVrQuitRequested = true;
|
||||
activeHmd->AcknowledgeQuit_Exiting();
|
||||
QMetaObject::invokeMethod(qApp, "quit");
|
||||
break;
|
||||
|
||||
case vr::VREvent_KeyboardDone:
|
||||
|
|
|
@ -214,6 +214,10 @@ void ViveControllerManager::renderHand(const controller::Pose& pose, gpu::Batch&
|
|||
void ViveControllerManager::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) {
|
||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
handleOpenVrEvents();
|
||||
if (openVrQuitRequested()) {
|
||||
deactivate();
|
||||
return;
|
||||
}
|
||||
|
||||
// because update mutates the internal state we need to lock
|
||||
userInputMapper->withLock([&, this]() {
|
||||
|
|
|
@ -15,6 +15,7 @@ Script.load("system/users.js");
|
|||
Script.load("system/mute.js");
|
||||
Script.load("system/goto.js");
|
||||
Script.load("system/hmd.js");
|
||||
Script.load("system/steam.js");
|
||||
Script.load("system/marketplace.js");
|
||||
Script.load("system/edit.js");
|
||||
Script.load("system/mod.js");
|
||||
|
|
112
scripts/system/assets/images/tools/steam-invite.svg
Normal file
112
scripts/system/assets/images/tools/steam-invite.svg
Normal file
|
@ -0,0 +1,112 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 50 200.1" style="enable-background:new 0 0 50 200.1;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#414042;}
|
||||
.st1{fill:#FFFFFF;}
|
||||
.st2{fill:#1E1E1E;}
|
||||
.st3{fill:#333333;}
|
||||
</style>
|
||||
<g id="Layer_2">
|
||||
<g>
|
||||
<g>
|
||||
<path class="st0" d="M50.1,146.1c0,2.2-1.8,4-4,4h-42c-2.2,0-4-1.8-4-4v-42c0-2.2,1.8-4,4-4h42c2.2,0,4,1.8,4,4V146.1z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path class="st0" d="M50,196.1c0,2.2-1.8,4-4,4H4c-2.2,0-4-1.8-4-4v-42c0-2.2,1.8-4,4-4h42c2.2,0,4,1.8,4,4V196.1z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path class="st1" d="M50,46c0,2.2-1.8,4-4,4H4c-2.2,0-4-1.8-4-4V4c0-2.2,1.8-4,4-4h42c2.2,0,4,1.8,4,4V46z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st2" d="M50,96.1c0,2.2-1.8,4-4,4H4c-2.2,0-4-1.8-4-4v-42c0-2.2,1.8-4,4-4h42c2.2,0,4,1.8,4,4V96.1z"/>
|
||||
</g>
|
||||
</g>
|
||||
<path class="st3" d="M14.32,21.31c0.16,0.05,0.25,0.08,0.33,0.11c1.27,0.53,2.55,1.07,3.82,1.59c0.19,0.08,0.28,0.19,0.34,0.38
|
||||
c0.49,1.6,1.94,2.57,3.55,2.37c1.59-0.19,2.8-1.51,2.89-3.16c0.01-0.22,0.08-0.35,0.25-0.47c1.17-0.83,2.33-1.67,3.5-2.51
|
||||
c0.11-0.08,0.27-0.14,0.41-0.14c2.31-0.06,4.14-1.88,4.23-4.29c0.09-2.34-1.64-4.19-3.73-4.49c-2.59-0.36-4.9,1.56-5,4.17
|
||||
c-0.01,0.14-0.05,0.3-0.13,0.41c-0.82,1.21-1.66,2.42-2.48,3.64c-0.11,0.16-0.22,0.22-0.41,0.23c-0.56,0.02-1.1,0.17-1.59,0.45
|
||||
c-0.1,0.06-0.27,0.08-0.37,0.03c-1.91-0.79-3.81-1.59-5.72-2.37c-0.2-0.08-0.27-0.18-0.25-0.4c0.22-2.12,0.95-4.04,2.22-5.74
|
||||
c1.96-2.62,4.57-4.26,7.83-4.6c5.01-0.53,8.91,1.43,11.48,5.76c3.52,5.94,0.91,13.76-5.42,16.52c-6.07,2.65-13.21-0.43-15.45-6.66
|
||||
C14.51,21.89,14.43,21.64,14.32,21.31z"/>
|
||||
<path class="st3" d="M29.28,18c-1.6,0-2.92-1.33-2.91-2.93c0.01-1.61,1.33-2.92,2.93-2.92c1.59,0.01,2.88,1.31,2.88,2.92
|
||||
C32.18,16.69,30.88,18,29.28,18z M29.27,17.28c1.21,0,2.21-0.99,2.21-2.2c0.01-1.22-0.98-2.22-2.18-2.23c-1.21,0-2.2,0.98-2.21,2.2
|
||||
C27.08,16.27,28.07,17.28,29.27,17.28z"/>
|
||||
<path class="st3" d="M19.8,23.57c0.47,0.19,0.89,0.37,1.3,0.54c1.01,0.41,2.06,0,2.45-0.97c0.39-0.95-0.05-1.99-1.04-2.41
|
||||
c-0.44-0.19-0.88-0.37-1.35-0.57c1.08-0.49,2.47,0.1,3.02,1.26c0.57,1.2,0.05,2.68-1.14,3.26C21.84,25.27,20.4,24.8,19.8,23.57z"/>
|
||||
<g>
|
||||
<path class="st3" d="M10.49,42.3v-6.38h1.24v6.38H10.49z"/>
|
||||
<path class="st3" d="M14.53,38.2v4.1h-1.24V35.9h0.96l3.33,4.19v-4.19h1.24v6.38h-1.01L14.53,38.2z"/>
|
||||
<path class="st3" d="M21.02,35.9l1.73,4.83l1.71-4.83h1.3l-2.49,6.39h-1.04l-2.51-6.39H21.02z"/>
|
||||
<path class="st3" d="M26.67,42.3v-6.38h1.24v6.38H26.67z"/>
|
||||
<path class="st3" d="M34.25,36.99h-2.03v5.3h-1.24v-5.3h-2.04V35.9h5.32V36.99z"/>
|
||||
<path class="st3" d="M39.71,41.21v1.09h-4.44V35.9h4.36v1.09h-3.11v1.54h2.69v1.01h-2.69v1.67H39.71z"/>
|
||||
</g>
|
||||
<path class="st1" d="M14.32,71.31c0.16,0.05,0.25,0.08,0.33,0.11c1.27,0.53,2.55,1.07,3.82,1.59c0.19,0.08,0.28,0.19,0.34,0.38
|
||||
c0.49,1.6,1.94,2.57,3.55,2.37c1.59-0.19,2.8-1.51,2.89-3.16c0.01-0.22,0.08-0.35,0.25-0.47c1.17-0.83,2.33-1.67,3.5-2.51
|
||||
c0.11-0.08,0.27-0.14,0.41-0.14c2.31-0.06,4.14-1.88,4.23-4.29c0.09-2.34-1.64-4.19-3.73-4.49c-2.59-0.36-4.9,1.56-5,4.17
|
||||
c-0.01,0.14-0.05,0.3-0.13,0.41c-0.82,1.21-1.66,2.42-2.48,3.64c-0.11,0.16-0.22,0.22-0.41,0.23c-0.56,0.02-1.1,0.17-1.59,0.45
|
||||
c-0.1,0.06-0.27,0.08-0.37,0.03c-1.91-0.79-3.81-1.59-5.72-2.37c-0.2-0.08-0.27-0.18-0.25-0.4c0.22-2.12,0.95-4.04,2.22-5.74
|
||||
c1.96-2.62,4.57-4.26,7.83-4.6c5.01-0.53,8.91,1.43,11.48,5.76c3.52,5.94,0.91,13.76-5.42,16.52c-6.07,2.65-13.21-0.43-15.45-6.66
|
||||
C14.51,71.9,14.43,71.65,14.32,71.31z"/>
|
||||
<path class="st1" d="M29.28,68c-1.6,0-2.92-1.33-2.91-2.93c0.01-1.61,1.33-2.92,2.93-2.92c1.59,0.01,2.88,1.31,2.88,2.92
|
||||
C32.18,66.69,30.88,68,29.28,68z M29.27,67.29c1.21,0,2.21-0.99,2.21-2.2c0.01-1.22-0.98-2.22-2.18-2.23c-1.21,0-2.2,0.98-2.21,2.2
|
||||
C27.08,66.28,28.07,67.28,29.27,67.29z"/>
|
||||
<path class="st1" d="M19.8,73.58c0.47,0.19,0.89,0.37,1.3,0.54c1.01,0.41,2.06,0,2.45-0.97c0.39-0.95-0.05-1.99-1.04-2.41
|
||||
c-0.44-0.19-0.88-0.37-1.35-0.57c1.08-0.49,2.47,0.1,3.02,1.26c0.57,1.2,0.05,2.68-1.14,3.26C21.84,75.27,20.4,74.8,19.8,73.58z"/>
|
||||
<g>
|
||||
<path class="st1" d="M10.49,92.3v-6.38h1.24v6.38H10.49z"/>
|
||||
<path class="st1" d="M14.53,88.2v4.1h-1.24v-6.39h0.96l3.33,4.19v-4.19h1.24v6.38h-1.01L14.53,88.2z"/>
|
||||
<path class="st1" d="M21.02,85.91l1.73,4.83l1.71-4.83h1.3l-2.49,6.39h-1.04l-2.51-6.39H21.02z"/>
|
||||
<path class="st1" d="M26.67,92.3v-6.38h1.24v6.38H26.67z"/>
|
||||
<path class="st1" d="M34.25,87h-2.03v5.3h-1.24V87h-2.04v-1.09h5.32V87z"/>
|
||||
<path class="st1" d="M39.71,91.21v1.09h-4.44v-6.39h4.36V87h-3.11v1.54h2.69v1.01h-2.69v1.67H39.71z"/>
|
||||
</g>
|
||||
<path class="st1" d="M14.32,121.41c0.16,0.05,0.25,0.08,0.33,0.11c1.27,0.53,2.55,1.07,3.82,1.59c0.19,0.08,0.28,0.19,0.34,0.38
|
||||
c0.49,1.6,1.94,2.57,3.55,2.37c1.59-0.19,2.8-1.51,2.89-3.16c0.01-0.22,0.08-0.35,0.25-0.47c1.17-0.83,2.33-1.67,3.5-2.51
|
||||
c0.11-0.08,0.27-0.14,0.41-0.14c2.31-0.06,4.14-1.88,4.23-4.29c0.09-2.34-1.64-4.19-3.73-4.49c-2.59-0.36-4.9,1.56-5,4.17
|
||||
c-0.01,0.14-0.05,0.3-0.13,0.41c-0.82,1.21-1.66,2.42-2.48,3.64c-0.11,0.16-0.22,0.22-0.41,0.23c-0.56,0.02-1.1,0.17-1.59,0.45
|
||||
c-0.1,0.06-0.27,0.08-0.37,0.03c-1.91-0.79-3.81-1.59-5.72-2.37c-0.2-0.08-0.27-0.18-0.25-0.4c0.22-2.12,0.95-4.04,2.22-5.74
|
||||
c1.96-2.62,4.57-4.26,7.83-4.6c5.01-0.53,8.91,1.43,11.48,5.76c3.52,5.94,0.91,13.76-5.42,16.52c-6.07,2.65-13.21-0.43-15.45-6.66
|
||||
C14.51,122,14.43,121.75,14.32,121.41z"/>
|
||||
<path class="st1" d="M29.28,118.1c-1.6,0-2.92-1.33-2.91-2.93c0.01-1.61,1.33-2.92,2.93-2.92c1.59,0.01,2.88,1.31,2.88,2.92
|
||||
C32.18,116.79,30.88,118.1,29.28,118.1z M29.27,117.39c1.21,0,2.21-0.99,2.21-2.2c0.01-1.22-0.98-2.22-2.18-2.23
|
||||
c-1.21,0-2.2,0.98-2.21,2.2C27.08,116.38,28.07,117.38,29.27,117.39z"/>
|
||||
<path class="st1" d="M19.8,123.68c0.47,0.19,0.89,0.37,1.3,0.54c1.01,0.41,2.06,0,2.45-0.97c0.39-0.95-0.05-1.99-1.04-2.41
|
||||
c-0.44-0.19-0.88-0.37-1.35-0.57c1.08-0.49,2.47,0.1,3.02,1.26c0.57,1.2,0.05,2.68-1.14,3.26C21.84,125.37,20.4,124.9,19.8,123.68z"
|
||||
/>
|
||||
<g>
|
||||
<path class="st1" d="M10.49,142.4v-6.38h1.24v6.38H10.49z"/>
|
||||
<path class="st1" d="M14.53,138.3v4.1h-1.24v-6.39h0.96l3.33,4.19v-4.19h1.24v6.38h-1.01L14.53,138.3z"/>
|
||||
<path class="st1" d="M21.02,136.01l1.73,4.83l1.71-4.83h1.3l-2.49,6.39h-1.04l-2.51-6.39H21.02z"/>
|
||||
<path class="st1" d="M26.67,142.4v-6.38h1.24v6.38H26.67z"/>
|
||||
<path class="st1" d="M34.25,137.1h-2.03v5.3h-1.24v-5.3h-2.04v-1.09h5.32V137.1z"/>
|
||||
<path class="st1" d="M39.71,141.31v1.09h-4.44v-6.39h4.36v1.09h-3.11v1.54h2.69v1.01h-2.69v1.67H39.71z"/>
|
||||
</g>
|
||||
<path class="st1" d="M14.32,171.51c0.16,0.05,0.25,0.08,0.33,0.11c1.27,0.53,2.55,1.07,3.82,1.59c0.19,0.08,0.28,0.19,0.34,0.38
|
||||
c0.49,1.6,1.94,2.57,3.55,2.37c1.59-0.19,2.8-1.51,2.89-3.16c0.01-0.22,0.08-0.35,0.25-0.47c1.17-0.83,2.33-1.67,3.5-2.51
|
||||
c0.11-0.08,0.27-0.14,0.41-0.14c2.31-0.06,4.14-1.88,4.23-4.29c0.09-2.34-1.64-4.19-3.73-4.49c-2.59-0.36-4.9,1.56-5,4.17
|
||||
c-0.01,0.14-0.05,0.3-0.13,0.41c-0.82,1.21-1.66,2.42-2.48,3.64c-0.11,0.16-0.22,0.22-0.41,0.23c-0.56,0.02-1.1,0.17-1.59,0.45
|
||||
c-0.1,0.06-0.27,0.08-0.37,0.03c-1.91-0.79-3.81-1.59-5.72-2.37c-0.2-0.08-0.27-0.18-0.25-0.4c0.22-2.12,0.95-4.04,2.22-5.74
|
||||
c1.96-2.62,4.57-4.26,7.83-4.6c5.01-0.53,8.91,1.43,11.48,5.76c3.52,5.94,0.91,13.76-5.42,16.52c-6.07,2.65-13.21-0.43-15.45-6.66
|
||||
C14.51,172.1,14.43,171.85,14.32,171.51z"/>
|
||||
<path class="st1" d="M29.28,168.2c-1.6,0-2.92-1.33-2.91-2.93c0.01-1.61,1.33-2.92,2.93-2.92c1.59,0.01,2.88,1.31,2.88,2.92
|
||||
C32.18,166.89,30.88,168.2,29.28,168.2z M29.27,167.49c1.21,0,2.21-0.99,2.21-2.2c0.01-1.22-0.98-2.22-2.18-2.23
|
||||
c-1.21,0-2.2,0.98-2.21,2.2C27.08,166.48,28.07,167.48,29.27,167.49z"/>
|
||||
<path class="st1" d="M19.8,173.78c0.47,0.19,0.89,0.37,1.3,0.54c1.01,0.41,2.06,0,2.45-0.97c0.39-0.95-0.05-1.99-1.04-2.41
|
||||
c-0.44-0.19-0.88-0.37-1.35-0.57c1.08-0.49,2.47,0.1,3.02,1.26c0.57,1.2,0.05,2.68-1.14,3.26C21.84,175.47,20.4,175,19.8,173.78z"/>
|
||||
<g>
|
||||
<path class="st1" d="M10.49,192.5v-6.38h1.24v6.38H10.49z"/>
|
||||
<path class="st1" d="M14.53,188.4v4.1h-1.24v-6.39h0.96l3.33,4.19v-4.19h1.24v6.38h-1.01L14.53,188.4z"/>
|
||||
<path class="st1" d="M21.02,186.11l1.73,4.83l1.71-4.83h1.3l-2.49,6.39h-1.04l-2.51-6.39H21.02z"/>
|
||||
<path class="st1" d="M26.67,192.5v-6.38h1.24v6.38H26.67z"/>
|
||||
<path class="st1" d="M34.25,187.2h-2.03v5.3h-1.24v-5.3h-2.04v-1.09h5.32V187.2z"/>
|
||||
<path class="st1" d="M39.71,191.41v1.09h-4.44v-6.39h4.36v1.09h-3.11v1.54h2.69v1.01h-2.69v1.67H39.71z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 8.2 KiB |
31
scripts/system/steam.js
Normal file
31
scripts/system/steam.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// steam.js
|
||||
// scripts/system/
|
||||
//
|
||||
// Created by Clement on 7/28/16
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system");
|
||||
|
||||
|
||||
var steamInviteButton = toolBar.addButton({
|
||||
objectName: "steamInvite",
|
||||
imageURL: Script.resolvePath("assets/images/tools/steam-invite.svg"),
|
||||
visible: Steam.isRunning,
|
||||
buttonState: 1,
|
||||
defaultState: 1,
|
||||
hoverState: 3,
|
||||
alpha: 0.9
|
||||
});
|
||||
|
||||
steamInviteButton.clicked.connect(function(){
|
||||
Steam.openInviteOverlay();
|
||||
});
|
||||
|
||||
Script.scriptEnding.connect(function () {
|
||||
toolBar.removeButton("steamInvite");
|
||||
});
|
Loading…
Reference in a new issue