diff --git a/interface/resources/icons/+android/avatar-a.svg b/interface/resources/icons/+android/avatar-a.svg new file mode 100755 index 0000000000..165b39943e --- /dev/null +++ b/interface/resources/icons/+android/avatar-a.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + diff --git a/interface/resources/icons/+android/avatar-i.svg b/interface/resources/icons/+android/avatar-i.svg new file mode 100755 index 0000000000..c1557487ea --- /dev/null +++ b/interface/resources/icons/+android/avatar-i.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + diff --git a/interface/resources/icons/+android/bubble-a.svg b/interface/resources/icons/+android/bubble-a.svg new file mode 100644 index 0000000000..fccc9c07ff --- /dev/null +++ b/interface/resources/icons/+android/bubble-a.svg @@ -0,0 +1,1022 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/interface/resources/icons/+android/bubble-i.svg b/interface/resources/icons/+android/bubble-i.svg new file mode 100644 index 0000000000..80c97d2704 --- /dev/null +++ b/interface/resources/icons/+android/bubble-i.svg @@ -0,0 +1,1022 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/interface/resources/icons/+android/button-a.svg b/interface/resources/icons/+android/button-a.svg new file mode 100644 index 0000000000..d469154775 --- /dev/null +++ b/interface/resources/icons/+android/button-a.svg @@ -0,0 +1,949 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/interface/resources/icons/+android/button.svg b/interface/resources/icons/+android/button.svg new file mode 100644 index 0000000000..8c19332064 --- /dev/null +++ b/interface/resources/icons/+android/button.svg @@ -0,0 +1,949 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/interface/resources/icons/+android/login-a.svg b/interface/resources/icons/+android/login-a.svg new file mode 100755 index 0000000000..8a7f097ed7 --- /dev/null +++ b/interface/resources/icons/+android/login-a.svg @@ -0,0 +1,990 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/interface/resources/icons/+android/login-i.svg b/interface/resources/icons/+android/login-i.svg new file mode 100755 index 0000000000..6f011e1d13 --- /dev/null +++ b/interface/resources/icons/+android/login-i.svg @@ -0,0 +1,990 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/interface/resources/icons/+android/tick.svg b/interface/resources/icons/+android/tick.svg new file mode 100644 index 0000000000..2c451c0994 --- /dev/null +++ b/interface/resources/icons/+android/tick.svg @@ -0,0 +1,950 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/interface/resources/qml/+android/AddressBarDialog.qml b/interface/resources/qml/+android/AddressBarDialog.qml index 0b12301561..50552f0d3b 100644 --- a/interface/resources/qml/+android/AddressBarDialog.qml +++ b/interface/resources/qml/+android/AddressBarDialog.qml @@ -33,7 +33,8 @@ Item { bar.visible = shown; sendToScript({method: 'shownChanged', params: { shown: shown }}); if (shown) { - updateLocationText(false); + addressLine.text=""; + updateLocationText(addressLine.text.length > 0); } } @@ -43,7 +44,7 @@ Item { } Component.onCompleted: { - updateLocationText(false); + updateLocationText(addressLine.text.length > 0); } HifiConstants { id: hifi } @@ -75,33 +76,33 @@ Item { HifiStyles.RalewayRegular { id: notice text: "YOUR LOCATION" - font.pixelSize: hifi.fonts.pixelSize * 2.15; + font.pixelSize: (hifi.fonts.pixelSize * 2.15)*(android.dimen.atLeast1440p?1:.75); color: "#2CD7FF" anchors { bottom: addressBackground.top - bottomMargin: 45 + bottomMargin: android.dimen.atLeast1440p?45:34 left: addressBackground.left - leftMargin: 60 + leftMargin: android.dimen.atLeast1440p?60:45 } } - property int inputAreaHeight: 210 + property int inputAreaHeight: android.dimen.atLeast1440p?210:156 property int inputAreaStep: (height - inputAreaHeight) / 2 ToolbarButton { id: homeButton - y: 280 + y: android.dimen.atLeast1440p?280:210 imageURL: "../../icons/home.svg" onClicked: { addressBarDialog.loadHome(); bar.shown = false; } anchors { - leftMargin: 75 + leftMargin: android.dimen.atLeast1440p?75:56 left: parent.left } - size: 150 + size: android.dimen.atLeast1440p?150:150//112 } ToolbarButton { @@ -110,10 +111,10 @@ Item { onClicked: addressBarDialog.loadBack(); anchors { left: homeButton.right - leftMargin: 70 + leftMargin: android.dimen.atLeast1440p?70:52 verticalCenter: homeButton.verticalCenter } - size: 150 + size: android.dimen.atLeast1440p?150:150 } ToolbarButton { id: forwardArrow; @@ -121,16 +122,16 @@ Item { onClicked: addressBarDialog.loadForward(); anchors { left: backArrow.right - leftMargin: 60 + leftMargin: android.dimen.atLeast1440p?60:45 verticalCenter: homeButton.verticalCenter } - size: 150 + size: android.dimen.atLeast1440p?150:150 } HifiStyles.FiraSansRegular { id: location; font.pixelSize: addressLine.font.pixelSize; - color: "gray"; + color: "lightgray"; clip: true; anchors.fill: addressLine; visible: addressLine.text.length === 0 @@ -139,24 +140,24 @@ Item { Rectangle { id: addressBackground - x: 780 - y: 280 - width: 1440 - height: 150 + x: android.dimen.atLeast1440p?780:585 + y: android.dimen.atLeast1440p?280:235 // tweaking by hand + width: android.dimen.atLeast1440p?1270:952 + height: android.dimen.atLeast1440p?150:112 color: "#FFFFFF" } TextInput { id: addressLine focus: true - x: 870 - y: 450 - width: 1350 - height: 120 + x: android.dimen.atLeast1440p?870:652 + y: android.dimen.atLeast1440p?300:245 // tweaking by hand + width: android.dimen.atLeast1440p?1200:900 + height: android.dimen.atLeast1440p?120:90 inputMethodHints: Qt.ImhNoPredictiveText //helperText: "Hint is here" anchors { - verticalCenter: homeButton.verticalCenter + //verticalCenter: addressBackground.verticalCenter } font.pixelSize: hifi.fonts.pixelSize * 3.75 onTextChanged: { diff --git a/interface/resources/qml/+android/LoginDialog.qml b/interface/resources/qml/+android/LoginDialog.qml new file mode 100644 index 0000000000..9eb2c74147 --- /dev/null +++ b/interface/resources/qml/+android/LoginDialog.qml @@ -0,0 +1,93 @@ +// +// LoginDialog.qml +// +// Created by David Rowe on 3 Jun 2015 +// 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" +import "windows" + +import "LoginDialog" + +ModalWindow { + id: root + HifiConstants { id: hifi } + + objectName: "LoginDialog" + implicitWidth: 1560 + implicitHeight: 450 + y:0 + destroyOnCloseButton: true + destroyOnHidden: true + visible: true + + property string iconText: "" + property int iconSize: 105 + + property string title: "" + property int titleWidth: 0 + + keyboardOverride: true // Disable ModalWindow's keyboard. + + function tryDestroy() { + root.destroy() + } + + LoginDialog { + id: loginDialog + + Loader { + id: bodyLoader + source: loginDialog.isSteamRunning() ? "LoginDialog/+android/SignInBody.qml" : "LoginDialog/+android/LinkAccountBody.qml" + } + } + + Component.onCompleted: { + this.anchors.centerIn = undefined; + this.y=150; + this.x=(parent.width - this.width)/2; + } + + Keys.onPressed: { + 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: + event.accepted = true + destroy() + break + + case Qt.Key_Enter: + case Qt.Key_Return: + event.accepted = true + break + } + } +} diff --git a/interface/resources/qml/LoginDialog/+android/LinkAccountBody.qml b/interface/resources/qml/LoginDialog/+android/LinkAccountBody.qml new file mode 100644 index 0000000000..7eced0c751 --- /dev/null +++ b/interface/resources/qml/LoginDialog/+android/LinkAccountBody.qml @@ -0,0 +1,290 @@ +// +// 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 + height: 300 + width: root.pane.width + property bool failAfterSignUp: false + function login() { + mainTextContainer.visible = false + toggleLoading(true) + loginDialog.login(usernameField.text, passwordField.text) + } + + property bool keyboardEnabled: false + property bool keyboardRaised: false + property bool punctuationMode: false + + onKeyboardRaisedChanged: d.resize(); + + QtObject { + id: d + readonly property int minWidth: 1440 + readonly property int maxWidth: 3840 + readonly property int minHeight: 150 + readonly property int maxHeight: 660 + + function resize() { + var targetWidth = Math.max(titleWidth, form.contentWidth); + var targetHeight = hifi.dimensions.contentSpacing.y + mainTextContainer.height + + 4 * hifi.dimensions.contentSpacing.y + form.height + + hifi.dimensions.contentSpacing.y + buttons.height; + + if (additionalInformation.visible) { + targetWidth = Math.max(targetWidth, additionalInformation.width); + targetHeight += hifi.dimensions.contentSpacing.y + additionalInformation.height + } + + parent.width = root.width = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth)); + parent.height = 420; + /*root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight)) + + (keyboardEnabled && keyboardRaised ? (200 + 2 * hifi.dimensions.contentSpacing.y) : hifi.dimensions.contentSpacing.y);*/ + } + } + + function toggleLoading(isLoading) { + linkAccountSpinner.visible = isLoading + form.visible = !isLoading + + if (loginDialog.isSteamRunning()) { + additionalInformation.visible = !isLoading + } + + leftButton.visible = !isLoading + buttons.visible = !isLoading + } + + BusyIndicator { + id: linkAccountSpinner + + anchors { + top: parent.top + horizontalCenter: parent.horizontalCenter + topMargin: hifi.dimensions.contentSpacing.y + } + + visible: false + running: true + + width: 144 + height: 144 + } + + ShortcutText { + id: mainTextContainer + anchors { + top: parent.top + left: parent.left + margins: 0 + topMargin: hifi.dimensions.contentSpacing.y / 2 + } + + 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: 0 // hifi.dimensions.contentSpacing.y + } + spacing: hifi.dimensions.contentSpacing.y / 2 + + TextField { + id: usernameField + anchors { + horizontalCenter: parent.horizontalCenter + } + width: 1080 + placeholderText: qsTr("Username or Email") + } + + TextField { + id: passwordField + anchors { + horizontalCenter: parent.horizontalCenter + } + width: 1080 + + placeholderText: qsTr("Password") + echoMode: TextInput.Password + } + } + + InfoItem { + id: additionalInformation + anchors { + top: form.bottom + left: parent.left + margins: 0 + topMargin: hifi.dimensions.contentSpacing.y + } + + visible: loginDialog.isSteamRunning() + + text: qsTr("Your steam account informations will not be exposed to other users.") + wrapMode: Text.WordWrap + color: hifi.colors.baseGrayHighlight + lineHeight: 3 + lineHeightMode: Text.ProportionalHeight + horizontalAlignment: Text.AlignHCenter + } + + // Override ScrollingWindow's keyboard that would be at very bottom of dialog. + Keyboard { + raised: keyboardEnabled && keyboardRaised + numeric: punctuationMode + anchors { + left: parent.left + right: parent.right + bottom: buttons.top + bottomMargin: keyboardRaised ? 2 * hifi.dimensions.contentSpacing.y : 0 + } + } + + Row { + id: leftButton + anchors { + left: parent.left + top: form.bottom + topMargin: hifi.dimensions.contentSpacing.y / 2 + } + + spacing: hifi.dimensions.contentSpacing.x + onHeightChanged: d.resize(); onWidthChanged: d.resize(); + + Button { + anchors.verticalCenter: parent.verticalCenter + + text: qsTr("Sign Up") + visible: !loginDialog.isSteamRunning() + + onClicked: { + bodyLoader.setSource("SignUpBody.qml") + bodyLoader.item.width = root.pane.width + bodyLoader.item.height = root.pane.height + } + } + } + + Row { + id: buttons + anchors { + right: parent.right + top: form.bottom + topMargin: hifi.dimensions.contentSpacing.y / 2 + } + spacing: hifi.dimensions.contentSpacing.x + onHeightChanged: d.resize(); onWidthChanged: d.resize(); + + Button { + id: linkAccountButton + anchors.verticalCenter: parent.verticalCenter + + text: qsTr(loginDialog.isSteamRunning() ? "Link Account" : "Login") + color: hifi.buttons.blue + + onClicked: { + Qt.inputMethod.hide(); + linkAccountBody.login(); + } + } + + Button { + anchors.verticalCenter: parent.verticalCenter + + text: qsTr("Cancel") + + onClicked: { + Qt.inputMethod.hide(); + root.destroy(); + } + } + } + + Component.onCompleted: { + root.title = qsTr("Sign Into High Fidelity") + root.iconText = "<" + keyboardEnabled = HMD.active; + d.resize(); + + if (failAfterSignUp) { + mainTextContainer.text = "Account created successfully." + mainTextContainer.visible = true + } + + //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 + toggleLoading(false) + } + 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") + toggleLoading(false) + } + } + + Keys.onPressed: { + if (!visible) { + return + } + + switch (event.key) { + case Qt.Key_Enter: + case Qt.Key_Return: + event.accepted = true + linkAccountBody.login() + break + } + } +} diff --git a/interface/resources/qml/LoginDialog/+android/SignUpBody.qml b/interface/resources/qml/LoginDialog/+android/SignUpBody.qml new file mode 100644 index 0000000000..3a44a8d741 --- /dev/null +++ b/interface/resources/qml/LoginDialog/+android/SignUpBody.qml @@ -0,0 +1,297 @@ +// +// SignUpBody.qml +// +// Created by Stephen Birarda on 7 Dec 2016 +// 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 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: signupBody + + clip: true + height: root.pane.height + width: root.pane.width + + function signup() { + mainTextContainer.visible = false + toggleLoading(true) + loginDialog.signup(emailField.text, usernameField.text, passwordField.text) + } + + property bool keyboardEnabled: false + property bool keyboardRaised: false + property bool punctuationMode: false + + onKeyboardRaisedChanged: d.resize(); + + QtObject { + id: d + readonly property int minWidth: 960 + readonly property int maxWidth: 2560 + readonly property int minHeight: 240 + readonly property int maxHeight: 1480 + + function resize() { + var targetWidth = Math.max(titleWidth, form.contentWidth); + var targetHeight = hifi.dimensions.contentSpacing.y + mainTextContainer.height + + 4 * hifi.dimensions.contentSpacing.y + form.height + + hifi.dimensions.contentSpacing.y + buttons.height; + + parent.width = root.width = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth)); + //parent.height = 650; + parent.height = root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight)); + + } + } + + function toggleLoading(isLoading) { + linkAccountSpinner.visible = isLoading + form.visible = !isLoading + + leftButton.visible = !isLoading + buttons.visible = !isLoading + } + + BusyIndicator { + id: linkAccountSpinner + + anchors { + top: parent.top + horizontalCenter: parent.horizontalCenter + topMargin: hifi.dimensions.contentSpacing.y + } + + visible: false + running: true + + width: 48 + height: 48 + } + + ShortcutText { + id: mainTextContainer + anchors { + top: parent.top + left: parent.left + margins: 0 + topMargin: hifi.dimensions.contentSpacing.y + } + + visible: false + + text: qsTr("There was an unknown error while creating your account.") + wrapMode: Text.WordWrap + color: hifi.colors.redAccent + horizontalAlignment: Text.AlignLeft + } + + Column { + id: form + anchors { + top: mainTextContainer.bottom + left: parent.left + margins: 0 + topMargin: 0; // 2 * hifi.dimensions.contentSpacing.y + } + spacing: hifi.dimensions.contentSpacing.y / 2 + + Row { + spacing: hifi.dimensions.contentSpacing.x + + TextField { + id: emailField + anchors { + verticalCenter: parent.verticalCenter + } + width: 780 + + placeholderText: "Email" + } + } + + Row { + spacing: hifi.dimensions.contentSpacing.x + + TextField { + id: usernameField + anchors { + verticalCenter: parent.verticalCenter + } + width: 780 + + placeholderText: "Username" + } + + ShortcutText { + anchors { + verticalCenter: parent.verticalCenter + } + + text: qsTr("No spaces / special chars.") + + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + + color: hifi.colors.blueAccent + } + } + + Row { + spacing: hifi.dimensions.contentSpacing.x + + TextField { + id: passwordField + anchors { + verticalCenter: parent.verticalCenter + } + width: 780 + + placeholderText: "Password" + echoMode: TextInput.Password + } + + ShortcutText { + anchors { + verticalCenter: parent.verticalCenter + } + + text: qsTr("At least 6 characters") + + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + + color: hifi.colors.blueAccent + } + } + + } + + // Override ScrollingWindow's keyboard that would be at very bottom of dialog. + Keyboard { + raised: keyboardEnabled && keyboardRaised + numeric: punctuationMode + anchors { + left: parent.left + right: parent.right + bottom: buttons.top + bottomMargin: keyboardRaised ? 2 * hifi.dimensions.contentSpacing.y : 0 + } + } + + Row { + id: leftButton + anchors { + left: parent.left + top: form.bottom + topMargin: hifi.dimensions.contentSpacing.y// / 2 + } + + spacing: hifi.dimensions.contentSpacing.x + onHeightChanged: d.resize(); onWidthChanged: d.resize(); + + Button { + anchors.verticalCenter: parent.verticalCenter + + text: qsTr("Existing User") + + onClicked: { + bodyLoader.setSource("LinkAccountBody.qml") + bodyLoader.item.width = root.pane.width + bodyLoader.item.height = root.pane.height + } + } + } + + Row { + id: buttons + anchors { + right: parent.right + top: form.bottom + topMargin: hifi.dimensions.contentSpacing.y / 2 + } + spacing: hifi.dimensions.contentSpacing.x + onHeightChanged: d.resize(); onWidthChanged: d.resize(); + + Button { + id: linkAccountButton + anchors.verticalCenter: parent.verticalCenter + + text: qsTr("Sign Up") + color: hifi.buttons.blue + + onClicked: signupBody.signup() + } + + Button { + anchors.verticalCenter: parent.verticalCenter + + text: qsTr("Cancel") + + onClicked: root.destroy() + } + } + + Component.onCompleted: { + root.title = qsTr("Create an Account") + root.iconText = "<" + keyboardEnabled = HMD.active; + d.resize(); + + emailField.forceActiveFocus(); + } + + Connections { + target: loginDialog + onHandleSignupCompleted: { + console.log("Sign Up Succeeded"); + + // now that we have an account, login with that username and password + loginDialog.login(usernameField.text, passwordField.text) + } + onHandleSignupFailed: { + console.log("Sign Up Failed") + toggleLoading(false) + + mainTextContainer.text = errorString + mainTextContainer.visible = true + + d.resize(); + } + onHandleLoginCompleted: { + bodyLoader.setSource("../WelcomeBody.qml", { "welcomeBack": false }) + bodyLoader.item.width = root.pane.width + bodyLoader.item.height = root.pane.height + } + onHandleLoginFailed: { + // we failed to login, show the LoginDialog so the user will try again + bodyLoader.setSource("LinkAccountBody.qml", { "failAfterSignUp": true }) + bodyLoader.item.width = root.pane.width + bodyLoader.item.height = root.pane.height + } + } + + Keys.onPressed: { + if (!visible) { + return + } + + switch (event.key) { + case Qt.Key_Enter: + case Qt.Key_Return: + event.accepted = true + signupBody.signup() + break + } + } +} diff --git a/interface/resources/qml/controls-uit/+android/ImageButton.qml b/interface/resources/qml/controls-uit/+android/ImageButton.qml new file mode 100644 index 0000000000..5ebf7cd3e9 --- /dev/null +++ b/interface/resources/qml/controls-uit/+android/ImageButton.qml @@ -0,0 +1,82 @@ +// +// ImageButton.qml +// interface/resources/qml/controls-uit +// +// Created by Gabriel Calero & Cristian Duarte on 12 Oct 2017 +// Copyright 2017 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.Layouts 1.3 +import "../styles-uit" as HifiStyles + +Item { + id: button + + property string text: "" + property string source : "" + property string hoverSource : "" + property real fontSize: 10 + property string fontColor: "#FFFFFF" + property string hoverFontColor: "#000000" + + signal clicked(); + + Rectangle { + color: "transparent" + anchors.fill: parent + Image { + id: image + anchors.fill: parent + source: button.source + } + + HifiStyles.FiraSansRegular { + id: buttonText + anchors.centerIn: parent + text: button.text + color: button.fontColor + font.pixelSize: button.fontSize + } + + MouseArea { + anchors.fill: parent + onClicked: button.clicked(); + onEntered: { + button.state = "hover state"; + } + onExited: { + button.state = "base state"; + } + } + + + } + states: [ + State { + name: "hover state" + PropertyChanges { + target: image + source: button.hoverSource + } + PropertyChanges { + target: buttonText + color: button.hoverFontColor + } + }, + State { + name: "base state" + PropertyChanges { + target: image + source: button.source + } + PropertyChanges { + target: buttonText + color: button.fontColor + } + } + ] +} \ No newline at end of file diff --git a/interface/resources/qml/controls-uit/Button.qml b/interface/resources/qml/controls-uit/Button.qml index 926e9c4fe5..e2b6097553 100644 --- a/interface/resources/qml/controls-uit/Button.qml +++ b/interface/resources/qml/controls-uit/Button.qml @@ -22,7 +22,7 @@ Original.Button { property int colorScheme: hifi.colorSchemes.light property string buttonGlyph: ""; - width: 120 + width: hifi.dimensions.buttonWidth height: hifi.dimensions.controlLineHeight HifiConstants { id: hifi } diff --git a/interface/resources/qml/desktop/+android/FocusHack.qml b/interface/resources/qml/desktop/+android/FocusHack.qml new file mode 100644 index 0000000000..38253fdec1 --- /dev/null +++ b/interface/resources/qml/desktop/+android/FocusHack.qml @@ -0,0 +1,26 @@ +// +// FocusHack.qml +// +// Created by Bradley Austin Davis on 21 Jan 2015 +// 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 + +FocusScope { + id: root + objectName: "FocusHack" + + TextInput { + id: textInput; + focus: true + width: 10; height: 10 + onActiveFocusChanged: root.destroy() + } + + function start() { + } +} diff --git a/interface/resources/qml/hifi/+android/AvatarOption.qml b/interface/resources/qml/hifi/+android/AvatarOption.qml new file mode 100644 index 0000000000..e7056baa36 --- /dev/null +++ b/interface/resources/qml/hifi/+android/AvatarOption.qml @@ -0,0 +1,117 @@ +// +// AvatarOption.qml +// interface/resources/qml/hifi/android +// +// Created by Cristian Duarte & Gabriel Calero on 12 Oct 2017 +// Copyright 2017 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.Layouts 1.3 +import QtQuick 2.5 +import "../controls-uit" as HifiControlsUit + +ColumnLayout { + id: itemRoot + + property string type: ""; + + property string thumbnailUrl: ""; + property string avatarUrl: ""; + property string avatarName: ""; + property bool avatarSelected: false; + + property string methodName: ""; + property string actionText: ""; + + spacing: 4*3 + signal sendToParentQml(var message); + + Image { + id: itemImage + Layout.preferredWidth: 250*3 + Layout.preferredHeight: 140*3 + source: thumbnailUrl + asynchronous: true + fillMode: Image.PreserveAspectFit + + MouseArea { + id: itemArea + anchors.fill: parent + hoverEnabled: true + enabled: true + onClicked: { + if (type=="avatar") { + if (!avatarSelected) sendToParentQml({ method: "selectAvatar", params: { avatarUrl: avatarUrl } }); + } else { + sendToParentQml({ method: methodName, params: { } }); + } + } + } + + } + + Text { + id: itemName + text: avatarName + color: "#FFFFFF" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + anchors.horizontalCenter: itemImage.horizontalCenter + font.pointSize: 5*3 + wrapMode: Text.WordWrap + width: parent + MouseArea { + id: itemNameArea + anchors.fill: parent + hoverEnabled: true + enabled: true + onClicked: { + if (type=="avatar") { + if (!avatarSelected) sendToParentQml({ method: "selectAvatar", params: { avatarUrl: avatarUrl } }); + } else { + sendToParentQml({ method: methodName, params: { } }); + } + } + } + } + + HifiControlsUit.ImageButton { + width: 140*3 + height: 35*3 + text: type=="extra"? actionText: "CHOOSE" + source: "../../../../icons/button.svg" + hoverSource: "../../../../icons/button-a.svg" + fontSize: 18*3 + fontColor: "#2CD8FF" + hoverFontColor: "#FFFFFF" + anchors { + horizontalCenter: itemName.horizontalCenter + } + visible: !avatarSelected + onClicked: { + if (type=="avatar") { + if (!avatarSelected) sendToParentQml({ method: "selectAvatar", params: { avatarUrl: avatarUrl } }); + } else { + sendToParentQml({ method: methodName, params: { } }); + } + } + } + + Image { + id: tickImage + width: 35*3 + height: 35*3 + source: "../../../icons/tick.svg" + anchors { + horizontalCenter: itemName.horizontalCenter + } + visible: avatarSelected + } + + Component.onCompleted:{ + sendToParentQml.connect(sendToScript); + } +} \ No newline at end of file diff --git a/interface/resources/qml/hifi/+android/HifiConstants.qml b/interface/resources/qml/hifi/+android/HifiConstants.qml index ee6d92ed38..fbdf60dcb0 100644 --- a/interface/resources/qml/hifi/+android/HifiConstants.qml +++ b/interface/resources/qml/hifi/+android/HifiConstants.qml @@ -10,6 +10,7 @@ // import QtQuick 2.4 +import QtQuick.Window 2.2 Item { @@ -20,26 +21,27 @@ Item { Item { id: dimen - readonly property real windowLessWidth: 126 - readonly property real windowLessHeight: 64 + readonly property bool atLeast1440p: Screen.width >= 2560 && Screen.height >= 1440 + readonly property real windowLessWidth: atLeast1440p?378:284 + readonly property real windowLessHeight: atLeast1440p?192:144 readonly property real windowZ: 100 - readonly property real headerHeight: 276 + readonly property real headerHeight: atLeast1440p?276:207 - readonly property real headerIconPosX: 90 - readonly property real headerIconPosY: 108 - readonly property real headerIconWidth: 111 - readonly property real headerIconHeight: 111 - readonly property real headerIconTitleDistance: 151 + readonly property real headerIconPosX: atLeast1440p?90:67 + readonly property real headerIconPosY: atLeast1440p?108:81 + readonly property real headerIconWidth: atLeast1440p?111:83 + readonly property real headerIconHeight: atLeast1440p?111:83 + readonly property real headerIconTitleDistance: atLeast1440p?151:113 - readonly property real headerHideWidth: 150 - readonly property real headerHideHeight: 150 - readonly property real headerHideRightMargin: 110 - readonly property real headerHideTopMargin: 90 - readonly property real headerHideIconWidth: 70 - readonly property real headerHideIconHeight: 45 - readonly property real headerHideTextTopMargin: 36 + readonly property real headerHideWidth: atLeast1440p?150:112 + readonly property real headerHideHeight: atLeast1440p?150:112 + readonly property real headerHideRightMargin: atLeast1440p?110:82 + readonly property real headerHideTopMargin: atLeast1440p?90:67 + readonly property real headerHideIconWidth: atLeast1440p?70:52 + readonly property real headerHideIconHeight: atLeast1440p?45:33 + readonly property real headerHideTextTopMargin: atLeast1440p?36:27 readonly property real botomHudWidth: 366 readonly property real botomHudHeight: 180 diff --git a/interface/resources/qml/hifi/+android/avatarSelection.qml b/interface/resources/qml/hifi/+android/avatarSelection.qml new file mode 100644 index 0000000000..3090204308 --- /dev/null +++ b/interface/resources/qml/hifi/+android/avatarSelection.qml @@ -0,0 +1,175 @@ +// +// avatarSelection.qml +// interface/resources/qml/android +// +// Created by Gabriel Calero & Cristian Duarte on 21 Sep 2017 +// Copyright 2017 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.Layouts 1.3 +import Hifi 1.0 + +import "../../styles" +import "." +import ".." +import ".." as QmlHifi +import "../../styles-uit" as HifiStyles + + +Item { + + id: top + + HifiConstants { id: android } + width: parent ? parent.width - android.dimen.windowLessWidth : 0 + height: parent ? parent.height - android.dimen.windowLessHeight : 0 + z: android.dimen.windowZ + anchors { horizontalCenter: parent.horizontalCenter; bottom: parent.bottom } + + signal sendToScript(var message); + + property bool shown: true + + onShownChanged: { + top.visible = shown; + } + + + HifiConstants { id: hifi } + HifiStyles.HifiConstants { id: hifiStyleConstants } + + property int cardWidth: 250 *3; + property int cardHeight: 240 *3; + property int gap: 14 *3; + + property var avatarsArray: []; + property var extraOptionsArray: []; + + function hide() { + shown = false; + sendToScript ({ method: "hide" }); + } + + Rectangle { + + width: parent ? parent.width : 0 + height: parent ? parent.height : 0 + + gradient: Gradient { + GradientStop { position: 0.0; color: android.color.gradientTop } + GradientStop { position: 1.0; color: android.color.gradientBottom } + } + + QmlHifi.WindowHeader { + id: header + iconSource: "../../../../icons/avatar-i.svg" + titleText: "AVATAR" + } + + ListModel { id: avatars } + + ListView { + id: scroll + height: 250*3 + property int stackedCardShadowHeight: 10*3; + spacing: gap; + clip: true; + anchors { + left: parent.left + right: parent.right + top: header.bottom + topMargin: gap + leftMargin: gap + rightMargin: gap + } + model: avatars; + orientation: ListView.Horizontal; + delegate: QmlHifi.AvatarOption { + type: model.type; + thumbnailUrl: model.thumbnailUrl; + avatarUrl: model.avatarUrl; + avatarName: model.avatarName; + avatarSelected: model.avatarSelected; + methodName: model.methodName; + actionText: model.actionText; + } + highlightMoveDuration: -1; + highlightMoveVelocity: -1; + } + + } + + function escapeRegExp(str) { + return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1"); + } + function replaceAll(str, find, replace) { + return str.replace(new RegExp(escapeRegExp(find), 'g'), replace); + } + + function refreshSelected(selectedAvatarUrl) { + // URL as ID? + avatarsArray.forEach(function (avatarData) { + avatarData.avatarSelected = (selectedAvatarUrl == avatarData.avatarUrl); + console.log('[avatarSelection] avatar : ', avatarData.avatarName, ' is selected? ' , avatarData.avatarSelected); + }); + } + + function addAvatar(name, thumbnailUrl, avatarUrl) { + avatarsArray.push({ + type: "avatar", + thumbnailUrl: thumbnailUrl, + avatarUrl: avatarUrl, + avatarName: name, + avatarSelected: false, + methodName: "", + actionText: "" + }); + } + + function showAvatars() { + avatars.clear(); + avatarsArray.forEach(function (avatarData) { + avatars.append(avatarData); + console.log('[avatarSelection] adding avatar to model: ', JSON.stringify(avatarData)); + }); + extraOptionsArray.forEach(function (extraData) { + avatars.append(extraData); + console.log('[avatarSelection] adding extra option to model: ', JSON.stringify(extraData)); + }); + } + + function addExtraOption(showName, thumbnailUrl, methodNameWhenClicked, actionText) { + extraOptionsArray.push({ + type: "extra", + thumbnailUrl: thumbnailUrl, + avatarUrl: "", + avatarName: showName, + avatarSelected: false, + methodName: methodNameWhenClicked, + actionText: actionText + }); + } + + function fromScript(message) { + //console.log("[CHAT] fromScript " + JSON.stringify(message)); + switch (message.type) { + case "addAvatar": + addAvatar(message.name, message.thumbnailUrl, message.avatarUrl); + break; + case "addExtraOption": + //(showName, thumbnailUrl, methodNameWhenClicked, actionText) + addExtraOption(message.showName, message.thumbnailUrl, message.methodNameWhenClicked, message.actionText); + break; + case "refreshSelected": + refreshSelected(message.selectedAvatarUrl); + break; + case "showAvatars": + showAvatars(); + break; + default: + } + } +} \ No newline at end of file diff --git a/interface/resources/qml/hifi/+android/bottombar.qml b/interface/resources/qml/hifi/+android/bottombar.qml index 2a34b7fe19..e861d441d9 100644 --- a/interface/resources/qml/hifi/+android/bottombar.qml +++ b/interface/resources/qml/hifi/+android/bottombar.qml @@ -41,6 +41,15 @@ Item { Styles.HifiConstants { id: hifi } HifiConstants { id: android } + MouseArea { + anchors.fill: parent + onEntered: { + Controller.setVPadEnabled(false); + } + onExited: { + Controller.setVPadEnabled(true); + } + } Rectangle { id: background diff --git a/interface/resources/qml/hifi/+android/button.qml b/interface/resources/qml/hifi/+android/button.qml index ec7af2ab92..4822b6bf33 100644 --- a/interface/resources/qml/hifi/+android/button.qml +++ b/interface/resources/qml/hifi/+android/button.qml @@ -40,6 +40,8 @@ Item { property bool isActive: false signal clicked() + signal entered() + signal exited() onIsActiveChanged: { if (button.isEntered) { @@ -118,6 +120,7 @@ Item { } onEntered: { button.isEntered = true; + button.entered(); if (button.isActive) { button.state = "hover active state"; } else { @@ -126,6 +129,7 @@ Item { } onExited: { button.isEntered = false; + button.exited() if (button.isActive) { button.state = "active state"; } else { diff --git a/interface/resources/qml/hifi/+android/modesbar.qml b/interface/resources/qml/hifi/+android/modesbar.qml index 8ce455c2c1..552ca80778 100644 --- a/interface/resources/qml/hifi/+android/modesbar.qml +++ b/interface/resources/qml/hifi/+android/modesbar.qml @@ -25,8 +25,8 @@ Item { } Component.onCompleted: { - width = 330; - height = 330; + width = 300 + 30; // That 30 is extra regardless the qty of items shown + height = 300 + 30; x=Window.innerWidth - width; } @@ -40,6 +40,12 @@ Item { var keys = Object.keys(properties).forEach(function (key) { button[key] = properties[key]; }); + button.entered.connect(function() { + Controller.setVPadEnabled(false); + }); + button.exited.connect(function() { + Controller.setVPadEnabled(true); + }); return button; } else if( component.status == Component.Error) { console.log("Load button errors " + component.errorString()); @@ -60,10 +66,10 @@ Item { function fromScript(message) { switch (message.type) { case "allButtonsShown": - modesbar.height = flowMain.children.length * 100 + 10; + modesbar.height = flowMain.children.length * 300 + 30; // That 30 is extra regardless the qty of items shown break; case "inactiveButtonsHidden": - modesbar.height = 100 + 10; + modesbar.height = 300 + 30; break; default: break; diff --git a/interface/resources/qml/styles-uit/+android/HifiConstants.qml b/interface/resources/qml/styles-uit/+android/HifiConstants.qml new file mode 100644 index 0000000000..d5fab57501 --- /dev/null +++ b/interface/resources/qml/styles-uit/+android/HifiConstants.qml @@ -0,0 +1,358 @@ +// +// HiFiConstants.qml +// +// Created by Bradley Austin Davis on 28 Apr 2015 +// 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 QtQuick 2.5 +import QtQuick.Window 2.2 + +Item { + readonly property alias colors: colors + readonly property alias colorSchemes: colorSchemes + readonly property alias dimensions: dimensions + readonly property alias fontSizes: fontSizes + readonly property alias glyphs: glyphs + readonly property alias icons: icons + readonly property alias buttons: buttons + readonly property alias effects: effects + + function glyphForIcon(icon) { + // Translates icon enum to glyph char. + var glyph; + switch (icon) { + case hifi.icons.information: + glyph = hifi.glyphs.info; + break; + case hifi.icons.question: + glyph = hifi.glyphs.question; + break; + case hifi.icons.warning: + glyph = hifi.glyphs.alert; + break; + case hifi.icons.critical: + glyph = hifi.glyphs.error; + break; + case hifi.icons.placemark: + glyph = hifi.glyphs.placemark; + break; + default: + glyph = hifi.glyphs.noIcon; + } + return glyph; + } + + Item { + id: colors + + // Base colors + readonly property color baseGray: "#393939" + readonly property color darkGray: "#121212" + readonly property color baseGrayShadow: "#252525" + readonly property color baseGrayHighlight: "#575757" + readonly property color lightGray: "#6a6a6a" + readonly property color lightGrayText: "#afafaf" + readonly property color faintGray: "#e3e3e3" + readonly property color primaryHighlight: "#00b4ef" + readonly property color blueHighlight: "#00b4ef" + readonly property color blueAccent: "#0093C5" + readonly property color redHighlight: "#EA4C5F" + readonly property color redAccent: "#C62147" + readonly property color greenHighlight: "#1ac567" + readonly property color greenShadow: "#359D85" + readonly property color orangeHighlight: "#FFC49C" + readonly property color orangeAccent: "#FF6309" + readonly property color indigoHighlight: "#C0D2FF" + readonly property color indigoAccent: "#9495FF" + readonly property color magentaHighlight: "#EF93D1" + readonly property color magentaAccent: "#A2277C" + readonly property color checkboxCheckedRed: "#FF0000" + readonly property color checkboxCheckedBorderRed: "#D00000" + readonly property color lightBlueHighlight: "#d6f6ff" + + // Semitransparent + readonly property color darkGray30: "#4d121212" + readonly property color darkGray0: "#00121212" + readonly property color baseGrayShadow60: "#99252525" + readonly property color baseGrayShadow50: "#80252525" + readonly property color baseGrayShadow25: "#40252525" + readonly property color baseGrayHighlight40: "#66575757" + readonly property color baseGrayHighlight15: "#26575757" + readonly property color lightGray50: "#806a6a6a" + readonly property color lightGrayText80: "#ccafafaf" + readonly property color faintGray80: "#cce3e3e3" + readonly property color faintGray50: "#80e3e3e3" + + // Other colors + readonly property color white: "#ffffff" + readonly property color gray: "#808080" + readonly property color black: "#000000" + readonly property color locked: "#252525" + // Semitransparent + readonly property color white50: "#80ffffff" + readonly property color white30: "#4dffffff" + readonly property color white25: "#40ffffff" + readonly property color transparent: "#00ffffff" + + // Control specific colors + readonly property color tableRowLightOdd: "#fafafa" + readonly property color tableRowLightEven: "#eeeeee" // Equivavlent to "#1a575757" over #e3e3e3 background + readonly property color tableRowDarkOdd: "#2e2e2e" // Equivalent to "#80393939" over #404040 background + readonly property color tableRowDarkEven: "#1c1c1c" // Equivalent to "#a6181818" over #404040 background + readonly property color tableBackgroundLight: tableRowLightEven + readonly property color tableBackgroundDark: tableRowDarkEven + readonly property color tableScrollHandleLight: "#DDDDDD" + readonly property color tableScrollHandleDark: "#707070" + readonly property color tableScrollBackgroundLight: tableRowLightOdd + readonly property color tableScrollBackgroundDark: "#323232" + readonly property color checkboxLightStart: "#ffffff" + readonly property color checkboxLightFinish: "#afafaf" + readonly property color checkboxDarkStart: "#7d7d7d" + readonly property color checkboxDarkFinish: "#6b6a6b" + readonly property color checkboxChecked: primaryHighlight + readonly property color checkboxCheckedBorder: "#36cdff" + readonly property color sliderGutterLight: "#d4d4d4" + readonly property color sliderGutterDark: "#252525" + readonly property color sliderBorderLight: "#afafaf" + readonly property color sliderBorderDark: "#7d7d7d" + readonly property color sliderLightStart: "#ffffff" + readonly property color sliderLightFinish: "#afafaf" + readonly property color sliderDarkStart: "#7d7d7d" + readonly property color sliderDarkFinish: "#6b6a6b" + readonly property color dropDownPressedLight: "#d4d4d4" + readonly property color dropDownPressedDark: "#afafaf" + readonly property color dropDownLightStart: "#ffffff" + readonly property color dropDownLightFinish: "#afafaf" + readonly property color dropDownDarkStart: "#7d7d7d" + readonly property color dropDownDarkFinish: "#6b6a6b" + readonly property color textFieldLightBackground: "#d4d4d4" + readonly property color tabBackgroundDark: "#252525" + readonly property color tabBackgroundLight: "#d4d4d4" + } + + Item { + id: colorSchemes + readonly property int light: 0 + readonly property int dark: 1 + readonly property int faintGray: 2 + } + + Item { + id: dimensions + readonly property bool largeScreen: Screen.width >= 1920 && Screen.height >= 1080 + readonly property real borderRadius: largeScreen ? 7.5 : 5.0 + readonly property real borderWidth: largeScreen ? 2 : 1 + readonly property vector2d contentMargin: Qt.vector2d(21, 21) + readonly property vector2d contentSpacing: Qt.vector2d(11, 14) + readonly property real labelPadding: 40 + readonly property real textPadding: 8 + readonly property real sliderHandleSize: 18 + readonly property real sliderGrooveHeight: 8 + readonly property real frameIconSize: 22 + readonly property real spinnerSize: 50 + readonly property real tablePadding: 12 + readonly property real tableRowHeight: largeScreen ? 26 : 23 + readonly property real tableHeaderHeight: 29 + readonly property vector2d modalDialogMargin: Qt.vector2d(50, 30) + readonly property real modalDialogTitleHeight: 120 + readonly property real controlLineHeight: 84 // Height of spinbox control on 1920 x 1080 monitor + readonly property real controlInterlineHeight: 21 // 75% of controlLineHeight + readonly property vector2d menuPadding: Qt.vector2d(14, 102) + readonly property real scrollbarBackgroundWidth: 20 + readonly property real scrollbarHandleWidth: scrollbarBackgroundWidth - 2 + readonly property real tabletMenuHeader: 90 + readonly property real buttonWidth: 360 + } + + Item { + id: fontSizes // In pixels + readonly property real overlayTitle: dimensions.largeScreen ? 54 : 42 + readonly property real tabName: dimensions.largeScreen ? 12 : 10 + readonly property real sectionName: dimensions.largeScreen ? 36 : 30 + readonly property real inputLabel: dimensions.largeScreen ? 14 : 10 + readonly property real textFieldInput: dimensions.largeScreen ? 48 : 36 + readonly property real textFieldInputLabel: dimensions.largeScreen ? 13 : 9 + readonly property real textFieldSearchIcon: dimensions.largeScreen ? 30 : 24 + readonly property real tableHeading: dimensions.largeScreen ? 12 : 10 + readonly property real tableHeadingIcon: dimensions.largeScreen ? 60 : 33 + readonly property real tableText: dimensions.largeScreen ? 15 : 12 + readonly property real buttonLabel: dimensions.largeScreen ? 42 : 27 + readonly property real iconButton: dimensions.largeScreen ? 13 : 9 + readonly property real listItem: dimensions.largeScreen ? 15 : 11 + readonly property real tabularData: dimensions.largeScreen ? 15 : 11 + readonly property real logs: dimensions.largeScreen ? 16 : 12 + readonly property real code: dimensions.largeScreen ? 16 : 12 + readonly property real rootMenu: dimensions.largeScreen ? 15 : 11 + readonly property real rootMenuDisclosure: dimensions.largeScreen ? 20 : 16 + readonly property real menuItem: dimensions.largeScreen ? 45 : 33 + readonly property real shortcutText: dimensions.largeScreen ? 39 : 27 + readonly property real carat: dimensions.largeScreen ? 38 : 30 + readonly property real disclosureButton: dimensions.largeScreen ? 30 : 22 + } + + Item { + id: icons + // Values per OffscreenUi::Icon + readonly property int none: 0 + readonly property int question: 1 + readonly property int information: 2 + readonly property int warning: 3 + readonly property int critical: 4 + readonly property int placemark: 5 + } + + Item { + id: buttons + readonly property int white: 0 + readonly property int blue: 1 + readonly property int red: 2 + readonly property int black: 3 + readonly property int none: 4 + readonly property int noneBorderless: 5 + readonly property int noneBorderlessWhite: 6 + readonly property int noneBorderlessGray: 7 + readonly property var textColor: [ colors.darkGray, colors.white, colors.white, colors.white, colors.white, colors.blueAccent, colors.white, colors.darkGray ] + readonly property var colorStart: [ colors.white, colors.primaryHighlight, "#d42043", "#343434", Qt.rgba(0, 0, 0, 0), Qt.rgba(0, 0, 0, 0), Qt.rgba(0, 0, 0, 0), Qt.rgba(0, 0, 0, 0) ] + readonly property var colorFinish: [ colors.lightGrayText, colors.blueAccent, "#94132e", colors.black, Qt.rgba(0, 0, 0, 0), Qt.rgba(0, 0, 0, 0), Qt.rgba(0, 0, 0, 0), Qt.rgba(0, 0, 0, 0) ] + readonly property var hoveredColor: [ colorStart[white], colorStart[blue], colorStart[red], colorFinish[black], colorStart[none], colorStart[noneBorderless], colorStart[noneBorderlessWhite], colorStart[noneBorderlessGray] ] + readonly property var pressedColor: [ colorFinish[white], colorFinish[blue], colorFinish[red], colorStart[black], colorStart[none], colorStart[noneBorderless], colorStart[noneBorderlessWhite], colorStart[noneBorderlessGray] ] + readonly property var disabledColorStart: [ colorStart[white], colors.baseGrayHighlight] + readonly property var disabledColorFinish: [ colorFinish[white], colors.baseGrayShadow] + readonly property var disabledTextColor: [ colors.lightGrayText, colors.baseGrayShadow] + readonly property int radius: 15 + } + + QtObject { + id: effects + readonly property int fadeInDuration: 300 + } + Item { + id: glyphs + readonly property string noIcon: "" + readonly property string hmd: "b" + readonly property string screen: "c" + readonly property string keyboard: "d" + readonly property string handControllers: "e" + readonly property string headphonesMic: "f" + readonly property string gamepad: "g" + readonly property string headphones: "h" + readonly property string mic: "i" + readonly property string upload: "j" + readonly property string script: "k" + readonly property string text: "l" + readonly property string cube: "m" + readonly property string sphere: "n" + readonly property string zone: "o" + readonly property string light: "p" + readonly property string web: "q" + readonly property string web2: "r" + readonly property string edit: "s" + readonly property string market: "t" + readonly property string directory: "u" + readonly property string menu: "v" + readonly property string close: "w" + readonly property string closeInverted: "x" + readonly property string pin: "y" + readonly property string pinInverted: "z" + readonly property string resizeHandle: "A" + readonly property string disclosureExpand: "B" + readonly property string reloadSmall: "a" + readonly property string closeSmall: "C" + readonly property string forward: "D" + readonly property string backward: "E" + readonly property string reload: "F" + readonly property string unmuted: "G" + readonly property string muted: "H" + readonly property string minimize: "I" + readonly property string maximize: "J" + readonly property string maximizeInverted: "K" + readonly property string disclosureButtonExpand: "L" + readonly property string disclosureButtonCollapse: "M" + readonly property string scriptStop: "N" + readonly property string scriptReload: "O" + readonly property string scriptRun: "P" + readonly property string scriptNew: "Q" + readonly property string hifiForum: "2" + readonly property string hifiLogoSmall: "S" + readonly property string avatar1: "T" + readonly property string placemark: "U" + readonly property string box: "V" + readonly property string community: "0" + readonly property string grabHandle: "X" + readonly property string search: "Y" + readonly property string disclosureCollapse: "Z" + readonly property string scriptUpload: "R" + readonly property string code: "W" + readonly property string avatar: "<" + readonly property string arrowsH: ":" + readonly property string arrowsV: ";" + readonly property string arrows: "`" + readonly property string compress: "!" + readonly property string expand: "\"" + readonly property string placemark1: "#" + readonly property string circle: "$" + readonly property string handPointer: "9" + readonly property string plusSquareO: "%" + readonly property string sliders: "&" + readonly property string square: "'" + readonly property string alignCenter: "8" + readonly property string alignJustify: ")" + readonly property string alignLeft: "*" + readonly property string alignRight: "^" + readonly property string bars: "7" + readonly property string circleSlash: "," + readonly property string sync: "()" + readonly property string key: "-" + readonly property string link: "." + readonly property string location: "/" + readonly property string caratR: "3" + readonly property string caratL: "4" + readonly property string caratDn: "5" + readonly property string caratUp: "6" + readonly property string folderLg: ">" + readonly property string folderSm: "?" + readonly property string levelUp: "1" + readonly property string info: "[" + readonly property string question: "]" + readonly property string alert: "+" + readonly property string home: "_" + readonly property string error: "=" + readonly property string settings: "@" + readonly property string trash: "{" + readonly property string objectGroup: "\ue000" + readonly property string cm: "}" + readonly property string msvg79: "~" + readonly property string deg: "\\" + readonly property string px: "|" + readonly property string editPencil: "\ue00d" + readonly property string vol_0: "\ue00e" + readonly property string vol_1: "\ue00f" + readonly property string vol_2: "\ue010" + readonly property string vol_3: "\ue011" + readonly property string vol_4: "\ue012" + readonly property string vol_x_0: "\ue013" + readonly property string vol_x_1: "\ue014" + readonly property string vol_x_2: "\ue015" + readonly property string vol_x_3: "\ue016" + readonly property string vol_x_4: "\ue017" + readonly property string source: "\ue01c" + readonly property string playback_play: "\ue01d" + readonly property string stop_square: "\ue01e" + readonly property string avatarTPose: "\ue01f" + readonly property string lock: "\ue006" + readonly property string checkmark: "\ue020" + readonly property string leftRightArrows: "\ue021" + readonly property string hfc: "\ue022" + readonly property string home2: "\ue023" + readonly property string walletKey: "\ue024" + readonly property string lightning: "\ue025" + readonly property string securityImage: "\ue026" + readonly property string wallet: "\ue027" + readonly property string paperPlane: "\ue028" + readonly property string passphrase: "\ue029" + } +} diff --git a/interface/resources/qml/styles-uit/HifiConstants.qml b/interface/resources/qml/styles-uit/HifiConstants.qml index 5da587ea57..53920759b1 100644 --- a/interface/resources/qml/styles-uit/HifiConstants.qml +++ b/interface/resources/qml/styles-uit/HifiConstants.qml @@ -165,6 +165,7 @@ Item { readonly property real scrollbarBackgroundWidth: 20 readonly property real scrollbarHandleWidth: scrollbarBackgroundWidth - 2 readonly property real tabletMenuHeader: 90 + readonly property real buttonWidth: 120 } Item { diff --git a/interface/resources/qml/windows/Frame.qml b/interface/resources/qml/windows/Frame.qml index c3b8399e01..4391c902ed 100644 --- a/interface/resources/qml/windows/Frame.qml +++ b/interface/resources/qml/windows/Frame.qml @@ -43,7 +43,8 @@ Item { Text { id: debugZ visible: DebugQML - text: window ? "Z: " + window.z : "" + color: "red" + text: (window ? "Z: " + window.z : "") + DebugQMLFile y: window ? window.height + 4 : 0 } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b4d1bf4c0a..ea060c2923 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -5968,6 +5968,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe scriptEngine->registerGlobalObject("ContextOverlay", DependencyManager::get().data()); scriptEngine->registerGlobalObject("Wallet", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("App", this); + qScriptRegisterMetaType(scriptEngine.data(), OverlayIDtoScriptValue, OverlayIDfromScriptValue); DependencyManager::get()->registerMetaTypes(scriptEngine.data()); diff --git a/interface/src/Application.h b/interface/src/Application.h index 8f0690bda1..5161c62a65 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -389,6 +389,8 @@ public slots: const QString getPreferredCursor() const { return _preferredCursor.get(); } void setPreferredCursor(const QString& cursor); + Q_INVOKABLE bool askBeforeSetAvatarUrl(const QString& avatarUrl) { return askToSetAvatarUrl(avatarUrl); } + private slots: void showDesktop(); void clearDomainOctreeDetails(); diff --git a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp index 8e1e6c2fba..53683870df 100644 --- a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp +++ b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp @@ -127,6 +127,10 @@ void TouchscreenVirtualPadDevice::debugPoints(const QTouchEvent* event, QString void TouchscreenVirtualPadDevice::touchBeginEvent(const QTouchEvent* event) { // touch begin here is a big begin -> begins both pads? maybe it does nothing debugPoints(event, " BEGIN ++++++++++++++++"); + auto& virtualPadManager = VirtualPad::Manager::instance(); + if (!virtualPadManager.isEnabled()) { + return; + } KeyboardMouseDevice::enableTouch(false); QScreen* eventScreen = event->window()->screen(); _screenWidthCenter = eventScreen->size().width() / 2; @@ -138,6 +142,10 @@ void TouchscreenVirtualPadDevice::touchBeginEvent(const QTouchEvent* event) { } void TouchscreenVirtualPadDevice::touchEndEvent(const QTouchEvent* event) { + auto& virtualPadManager = VirtualPad::Manager::instance(); + if (!virtualPadManager.isEnabled()) { + return; + } // touch end here is a big reset -> resets both pads _touchPointCount = 0; KeyboardMouseDevice::enableTouch(true); @@ -148,6 +156,12 @@ void TouchscreenVirtualPadDevice::touchEndEvent(const QTouchEvent* event) { } void TouchscreenVirtualPadDevice::touchUpdateEvent(const QTouchEvent* event) { + auto& virtualPadManager = VirtualPad::Manager::instance(); + if (!virtualPadManager.isEnabled()) { + touchLeftEnd(); + touchRightEnd(); + return; + } _touchPointCount = event->touchPoints().count(); const QList& tPoints = event->touchPoints(); @@ -224,6 +238,10 @@ void TouchscreenVirtualPadDevice::touchRightEnd() { } void TouchscreenVirtualPadDevice::touchGestureEvent(const QGestureEvent* event) { + auto& virtualPadManager = VirtualPad::Manager::instance(); + if (!virtualPadManager.isEnabled()) { + return; + } if (QGesture* gesture = event->gesture(Qt::PinchGesture)) { QPinchGesture* pinch = static_cast(gesture); _pinchScale = pinch->totalScaleFactor(); diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp index 4829e5c85b..144671fca8 100755 --- a/libraries/render-utils/src/RenderForwardTask.cpp +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -37,6 +37,7 @@ using namespace render; extern void initForwardPipelines(ShapePlumber& plumber, const render::ShapePipeline::BatchSetter& batchSetter, const render::ShapePipeline::ItemSetter& itemSetter); +extern void initOverlay3DPipelines(render::ShapePlumber& plumber, bool depthTest = false); void RenderForwardTask::build(JobModel& task, const render::Varying& input, render::Varying& output) { auto items = input.get(); @@ -45,6 +46,7 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend // Prepare the ShapePipelines ShapePlumberPointer shapePlumber = std::make_shared(); initForwardPipelines(*shapePlumber, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter()); + initOverlay3DPipelines(*shapePlumber); // Extract opaques / transparents / lights / metas / overlays / background const auto& opaques = items.get0()[RenderFetchCullSortTask::OPAQUE_SHAPE]; diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 221f5013bf..287978bbd3 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -658,8 +658,10 @@ void OffscreenUi::createDesktop(const QUrl& url) { #ifdef DEBUG getSurfaceContext()->setContextProperty("DebugQML", QVariant(true)); + getSurfaceContext()->setContextProperty("DebugQMLFile", QVariant(url.toString())); #else getSurfaceContext()->setContextProperty("DebugQML", QVariant(false)); + getSurfaceContext()->setContextProperty("DebugQMLFile", QVariant("")); #endif load(url, [=](QQmlContext* context, QObject* newObject) { diff --git a/scripts/system/+android/avatarSelection.js b/scripts/system/+android/avatarSelection.js new file mode 100644 index 0000000000..be58f61ac2 --- /dev/null +++ b/scripts/system/+android/avatarSelection.js @@ -0,0 +1,159 @@ +"use strict"; +// +// avatarSelection.js +// scripts/system/ +// +// Created by Gabriel Calero & Cristian Duarte on 21 Sep 2017 +// Copyright 2017 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 window; + +var logEnabled = true; +var isVisible = false; + +function printd(str) { + if (logEnabled) + print("[avatarSelection.js] " + str); +} + +function fromQml(message) { // messages are {method, params}, like json-rpc. See also sendToQml. + var data; + printd("fromQml " + JSON.stringify(message)); + switch (message.method) { + case 'selectAvatar': + // use this message.params.avatarUrl + printd("Selected Avatar: [" + message.params.avatarUrl + "]"); + App.askBeforeSetAvatarUrl(message.params.avatarUrl); + break; + case 'openAvatarMarket': + // good + App.openUrl("https://metaverse.highfidelity.com/marketplace?category=avatars"); + break; + case 'hide': + module.exports.onHidden(); + break; + default: + print('[avatarSelection.js] Unrecognized message from avatarSelection.qml:', JSON.stringify(message)); + } +} + +function sendToQml(message) { + if (!window) { + print("[avatarSelection.js] There is no window object"); + return; + } + window.sendToQml(message); +} + +function refreshSelected(currentAvatarURL) { + sendToQml({ + type: "refreshSelected", + selectedAvatarUrl: currentAvatarURL + }); + + sendToQml({ + type: "showAvatars" + }); +} + +function init() { + if (!window) { + print("[avatarSelection.js] There is no window object for init()"); + return; + } + var DEFAULT_AVATAR_URL = "http://mpassets.highfidelity.com/7fe80a1e-f445-4800-9e89-40e677b03bee-v3/mannequin.fst"; + sendToQml({ + type: "addAvatar", + name: "Wooden Mannequin", + thumbnailUrl: "https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/previews/7fe80a1e-f445-4800-9e89-40e677b03bee/thumbnail/hifi-mp-7fe80a1e-f445-4800-9e89-40e677b03bee.jpg", + avatarUrl: DEFAULT_AVATAR_URL + }); + sendToQml({ + type: "addAvatar", + name: "Cody", + thumbnailUrl: "https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/previews/8c859fca-4cbd-4e82-aad1-5f4cb0ca5d53/thumbnail/hifi-mp-8c859fca-4cbd-4e82-aad1-5f4cb0ca5d53.jpg", + avatarUrl: "http://mpassets.highfidelity.com/8c859fca-4cbd-4e82-aad1-5f4cb0ca5d53-v1/cody.fst" + }); + sendToQml({ + type: "addAvatar", + name: "Mixamo Will", + thumbnailUrl: "https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/previews/d029ae8d-2905-4eb7-ba46-4bd1b8cb9d73/thumbnail/hifi-mp-d029ae8d-2905-4eb7-ba46-4bd1b8cb9d73.jpg", + avatarUrl: "http://mpassets.highfidelity.com/d029ae8d-2905-4eb7-ba46-4bd1b8cb9d73-v1/4618d52e711fbb34df442b414da767bb.fst" + }); + sendToQml({ + type: "addAvatar", + name: "Albert", + thumbnailUrl: "https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/previews/1e57c395-612e-4acd-9561-e79dbda0bc49/thumbnail/hifi-mp-1e57c395-612e-4acd-9561-e79dbda0bc49.jpg", + avatarUrl: "http://mpassets.highfidelity.com/1e57c395-612e-4acd-9561-e79dbda0bc49-v1/albert.fst" + }); + /* We need to implement the wallet, so let's skip this for the moment + sendToQml({ + type: "addExtraOption", + showName: "More choices", + thumbnailUrl: "../../../images/moreAvatars.png", + methodNameWhenClicked: "openAvatarMarket", + actionText: "MARKETPLACE" + }); + */ + var currentAvatarURL = Settings.getValue('Avatar/fullAvatarURL', DEFAULT_AVATAR_URL); + printd("Default Avatar: [" + DEFAULT_AVATAR_URL + "]"); + printd("Current Avatar: [" + currentAvatarURL + "]"); + if (!currentAvatarURL || 0 === currentAvatarURL.length) { + currentAvatarURL = DEFAULT_AVATAR_URL; + } + refreshSelected(currentAvatarURL); +} + +module.exports = { + init: function() { + window = new QmlFragment({ + qml: "hifi/avatarSelection.qml", + visible: false + }); + /*, + visible: false*/ + if (window) { + window.fromQml.connect(fromQml); + } + init(); + }, + show: function() { + if (window) { + window.setVisible(true); + isVisible = true; + } + }, + hide: function() { + if (window) { + window.setVisible(false); + } + isVisible = false; + }, + destroy: function() { + if (window) { + window.fromQml.disconnect(fromQml); + window.close(); + window = null; + } + }, + isVisible: function() { + return isVisible; + }, + width: function() { + return window ? window.size.x : 0; + }, + height: function() { + return window ? window.size.y : 0; + }, + position: function() { + return window && isVisible ? window.position : null; + }, + refreshSelectedAvatar: function(currentAvatarURL) { + refreshSelected(currentAvatarURL); + }, + onHidden: function() { } +}; diff --git a/scripts/system/+android/bottombar.js b/scripts/system/+android/bottombar.js index e58840ad6f..5f82886c8a 100644 --- a/scripts/system/+android/bottombar.js +++ b/scripts/system/+android/bottombar.js @@ -14,8 +14,12 @@ var bottombar; var bottomHudOptionsBar; var gotoBtn; +var avatarBtn; +var bubbleBtn; +var loginBtn; var gotoScript = Script.require('./goto.js'); +var avatarSelection = Script.require('./avatarSelection.js'); var logEnabled = false; @@ -34,15 +38,20 @@ function init() { hideAddressBar(); } }); + avatarSelection.init(); + App.fullAvatarURLChanged.connect(processedNewAvatar); setupBottomBar(); setupBottomHudOptionsBar(); raiseBottomBar(); + GlobalServices.connected.connect(handleLogin); + GlobalServices.disconnected.connect(handleLogout); } function shutdown() { + App.fullAvatarURLChanged.disconnect(processedNewAvatar); } function setupBottomBar() { @@ -60,6 +69,32 @@ function setupBottomBar() { } }); + avatarBtn = bottombar.addButton({ + icon: "icons/avatar-i.svg", + activeIcon: "icons/avatar-a.svg", + bgOpacity: 0, + height: 240, + width: 294, + hoverBgOpacity: 0, + activeBgOpacity: 0, + activeHoverBgOpacity: 0, + iconSize: 108, + textSize: 45, + text: "AVATAR" + }); + avatarBtn.clicked.connect(function() { + printd("Avatar button clicked"); + if (!avatarSelection.isVisible()) { + showAvatarSelection(); + } else { + hideAvatarSelection(); + } + }); + avatarSelection.onHidden = function() { + if (avatarBtn) { + avatarBtn.isActive = false; + } + }; gotoBtn = bottombar.addButton({ icon: "icons/goto-i.svg", @@ -69,7 +104,7 @@ function setupBottomBar() { activeBgOpacity: 0, activeHoverBgOpacity: 0, height: 240, - width: 300, + width: 294, iconSize: 108, textSize: 45, text: "GO TO" @@ -83,6 +118,42 @@ function setupBottomBar() { } }); + bubbleBtn = bottombar.addButton({ + icon: "icons/bubble-i.svg", + activeIcon: "icons/bubble-a.svg", + bgOpacity: 0, + hoverBgOpacity: 0, + activeBgOpacity: 0, + activeHoverBgOpacity: 0, + height: 240, + width: 294, + iconSize: 108, + textSize: 45, + text: "BUBBLE" + }); + + bubbleBtn.clicked.connect(function() { + Users.toggleIgnoreRadius(); + bubbleBtn.editProperties({isActive: Users.getIgnoreRadiusEnabled()}); + }); + + loginBtn = bottombar.addButton({ + icon: "icons/login-i.svg", + activeIcon: "icons/login-a.svg", + height: 240, + width: 294, + iconSize: 108, + textSize: 45, + text: Account.isLoggedIn() ? "LOG OUT" : "LOG IN" + }); + loginBtn.clicked.connect(function() { + if (!Account.isLoggedIn()) { + Account.checkAndSignalForAccessToken(); + } else { + Menu.triggerOption("Login / Sign Up"); + } + }); + // TODO: setup all the buttons or provide a dynamic interface raiseBottomBar(); @@ -148,10 +219,43 @@ function hideAddressBar() { gotoBtn.isActive = false; } +function showAvatarSelection() { + avatarSelection.show(); + avatarBtn.isActive = true; +} +function hideAvatarSelection() { + avatarSelection.hide(); + avatarBtn.isActive = false; +} + +// TODO: Move to avatarSelection.js and make it possible to hide the window from there AND switch the button state here too +function processedNewAvatar(url, modelName) { + avatarSelection.refreshSelectedAvatar(url); + hideAvatarSelection(); +} + +function handleLogin() { + Script.setTimeout(function() { + if (Account.isLoggedIn()) { + MyAvatar.displayName=Account.getUsername(); + } + }, 2000); + if (loginBtn) { + loginBtn.editProperties({text: "LOG OUT"}); + } +} +function handleLogout() { + MyAvatar.displayName=""; + if (loginBtn) { + loginBtn.editProperties({text: "LOG IN"}); + } +} Script.scriptEnding.connect(function () { shutdown(); + GlobalServices.connected.disconnect(handleLogin); + GlobalServices.disconnected.disconnect(handleLogout); }); init(); diff --git a/scripts/system/+android/radar.js b/scripts/system/+android/radar.js index 9fa07178f6..54e1e51945 100644 --- a/scripts/system/+android/radar.js +++ b/scripts/system/+android/radar.js @@ -29,12 +29,13 @@ var MOVE_BY = 1; // Swipe/Drag vars var PINCH_INCREMENT_FIRST = 0.4; // 0.1 meters zoom in - out var PINCH_INCREMENT = 0.4; // 0.1 meters zoom in - out -var RADAR_HEIGHT_MAX_PLUS_AVATAR = 40; +var RADAR_HEIGHT_MAX_PLUS_AVATAR = 80; var RADAR_HEIGHT_MIN_PLUS_AVATAR = 2; -var RADAR_CAMERA_DISTANCE_TO_ICONS = 0.5; // Icons are near the camera to prevent the LOD manager dismissing them +var RADAR_CAMERA_DISTANCE_TO_ICONS = 1.5; // Icons are near the camera to prevent the LOD manager dismissing them var RADAR_ICONS_APPARENT_DISTANCE_TO_AVATAR_BASE = 1; // How much above the avatar base should the icon appear -var AVATAR_DISPLAY_NAME_HEIGHT = 38; -var AVATAR_DISPLAY_NAME_CHAR_WIDTH = 18; +var AVATAR_DISPLAY_NAME_HEIGHT = 106; +var AVATAR_DISPLAY_NAME_CHAR_WIDTH = 48; +var AVATAR_DISPLAY_NAME_FONT_SIZE = 50; var lastDragAt; var lastDeltaDrag; @@ -734,14 +735,15 @@ function saveAvatarData(QUuid) { if (avatarsData[QUuid] != undefined) { avatarsData[QUuid].position = avat.position; } else { - var avatarIcon = Overlays.addOverlay("image3d", { - subImage: { x: 0, y: 0, width: 150, height: 142}, - url: getAvatarIconForUser(QUuid), - dimensions: ICON_ENTITY_DEFAULT_DIMENSIONS, - visible: false, - ignoreRayIntersection: false, - orientation: Quat.fromPitchYawRollDegrees(-90,0,0) - }); + var avatarIcon = Overlays.addOverlay("circle3d", { + color: uniqueColor.convertHexToRGB(uniqueColor.getColor(QUuid)), + dimensions: ICON_ENTITY_DEFAULT_DIMENSIONS, + rotation: Quat.fromPitchYawRollDegrees(90, 0, 0), + innerRadius: 1.8, + outerRadius: 2, + isSolid: true, + visible: false + }); var needRefresh = !avat || !avat.displayName; var displayName = avat && avat.displayName ? avat.displayName : "Unknown"; @@ -752,7 +754,7 @@ function saveAvatarData(QUuid) { color: { red: 255, green: 255, blue: 255}, backgroundAlpha: 0.0, textRaiseColor: { red: 0, green: 0, blue: 0}, - font: {size: 68, bold: true}, + font: {size: AVATAR_DISPLAY_NAME_FONT_SIZE, bold: true}, visible: false, text: displayName, textAlignCenter: true @@ -809,19 +811,24 @@ function avatarRemoved(QUuid) { ********************************************************************************************************/ var myAvatarIcon; var myAvatarName; - +function distanceForCameraHeight(h) { + if (h < 30) return 1; + if (h < 40) return 2; + if (h < 50) return 2.5; + return 5; +} function renderMyAvatarIcon() { + var commonY = Camera.position.y - distanceForCameraHeight(Camera.position.y); var iconPos = findLineToHeightIntersectionCoords( MyAvatar.position.x, MyAvatar.position.y + RADAR_ICONS_APPARENT_DISTANCE_TO_AVATAR_BASE, MyAvatar.position.z, Camera.position.x, Camera.position.y, Camera.position.z, - Camera.position.y - RADAR_CAMERA_DISTANCE_TO_ICONS); + commonY); if (!iconPos) { printd("avatarmy icon pos null"); return;} var iconDimensions = avatarIconPlaneDimensions(); var avatarPos = MyAvatar.position; var cameraPos = Camera.position; - var commonY = Camera.position.y - RADAR_CAMERA_DISTANCE_TO_ICONS; var borderPoints = [ computePointAtPlaneY(0, 0, commonY), computePointAtPlaneY(Window.innerWidth, Window.innerHeight, commonY) @@ -833,25 +840,26 @@ function renderMyAvatarIcon() { var x = (p1.x - borderPoints[0].x) * (Window.innerWidth) / (borderPoints[1].x - borderPoints[0].x); var y = (p1.z - borderPoints[0].z) * (Window.innerHeight) / (borderPoints[1].z - borderPoints[0].z); - if (!myAvatarIcon && MyAvatar.sessionUUID) { - myAvatarIcon = Overlays.addOverlay("image3d", { - subImage: { x: 0, y: 0, width: 150, height: 142}, - url: getAvatarIconForUser(MyAvatar.sessionUUID), - dimensions: ICON_ENTITY_DEFAULT_DIMENSIONS, - visible: false, - ignoreRayIntersection: false, - orientation: Quat.fromPitchYawRollDegrees(-90,0,0) - }); + if (!myAvatarIcon && MyAvatar.SELF_ID) { + myAvatarIcon = Overlays.addOverlay("circle3d", { + color: uniqueColor.convertHexToRGB(uniqueColor.getColor(MyAvatar.SELF_ID)), + dimensions: ICON_ENTITY_DEFAULT_DIMENSIONS, + rotation: Quat.fromPitchYawRollDegrees(90, 0, 0), + innerRadius: 1.8, + outerRadius: 2, + isSolid: true, + visible: false + }); } if (!myAvatarName) { myAvatarName = Overlays.addOverlay("text", { - width: 40, + width: 100, height: AVATAR_DISPLAY_NAME_HEIGHT, textAlignCenter: true, color: { red: 255, green: 255, blue: 255}, backgroundAlpha: 0.0, - font: {size: 68, bold: true}, + font: {size: AVATAR_DISPLAY_NAME_FONT_SIZE, bold: true}, textRaiseColor: { red: 0, green: 0, blue: 0}, visible: false, text: "Me" @@ -896,7 +904,7 @@ function hideAllAvatarIcons() { function renderAllOthersAvatarIcons() { var avatarPos; var iconDimensions = avatarIconPlaneDimensions(); - var commonY = Camera.position.y - RADAR_CAMERA_DISTANCE_TO_ICONS; + var commonY = Camera.position.y - distanceForCameraHeight(Camera.position.y); var borderPoints = [ computePointAtPlaneY(0, 0, commonY), computePointAtPlaneY(Window.innerWidth, Window.innerHeight, commonY) @@ -907,18 +915,18 @@ function renderAllOthersAvatarIcons() { if (AvatarList.getAvatar(QUuid) != null) { avatarPos = AvatarList.getAvatar(QUuid).position; - var cameraPos = Camera.position; - var p1 = findLineToHeightIntersectionCoords(avatarPos.x, avatarPos.y, avatarPos.z, + var cameraPos = Camera.position; + var p1 = findLineToHeightIntersectionCoords(avatarPos.x, avatarPos.y, avatarPos.z, cameraPos.x, cameraPos.y, cameraPos.z, commonY); - var x = (p1.x - borderPoints[0].x) * (Window.innerWidth) / (borderPoints[1].x - borderPoints[0].x); - var y = (p1.z - borderPoints[0].z) * (Window.innerHeight) / (borderPoints[1].z - borderPoints[0].z); + var x = (p1.x - borderPoints[0].x) * (Window.innerWidth) / (borderPoints[1].x - borderPoints[0].x); + var y = (p1.z - borderPoints[0].z) * (Window.innerHeight) / (borderPoints[1].z - borderPoints[0].z); if (avatarsData[QUuid].icon != undefined) { var iconPos = findLineToHeightIntersectionCoords( avatarPos.x, avatarPos.y + RADAR_ICONS_APPARENT_DISTANCE_TO_AVATAR_BASE, avatarPos.z, Camera.position.x, Camera.position.y, Camera.position.z, - Camera.position.y - RADAR_CAMERA_DISTANCE_TO_ICONS); + commonY); if (!iconPos) { print ("avatar icon pos bad for " + QUuid); continue; } if (avatarsData[QUuid].needRefresh) { var avat = AvatarList.getAvatar(QUuid); @@ -1100,6 +1108,8 @@ function startRadar() { Camera.orientation = Quat.fromPitchYawRollDegrees(-90,0,0); radar = true; + Controller.setVPadEnabled(false); // this was done before in CompositeExtra in the DisplayPlugin (Checking for camera not independent, not radar mode) + connectRadarModeEvents(); } @@ -1108,6 +1118,8 @@ function endRadar() { Camera.mode = "first person"; radar = false; + Controller.setVPadEnabled(true); + disconnectRadarModeEvents(); hideAllEntitiesIcons(); hideAllAvatarIcons(); diff --git a/scripts/system/+android/uniqueColor.js b/scripts/system/+android/uniqueColor.js index c296b6c87d..a2741642d2 100644 --- a/scripts/system/+android/uniqueColor.js +++ b/scripts/system/+android/uniqueColor.js @@ -41,6 +41,14 @@ function getColorForId(uuid) { module.exports = { getColor: function(id) { - return getColorForId(id); + return getColorForId(id); + }, + convertHexToRGB: function(hex) { + var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + return result ? { + red: parseInt(result[1], 16), + green: parseInt(result[2], 16), + blue: parseInt(result[3], 16) + } : null; } };