Merge branch 'master' of git://github.com/highfidelity/hifi into outline

This commit is contained in:
Olivier Prat 2017-09-06 19:08:37 +02:00
commit 17e992bd14
26 changed files with 584 additions and 357 deletions

View file

@ -6,7 +6,14 @@
<title>Welcome to Interface</title>
<style>
body {
@font-face {
font-family: 'Raleway Light';
src: url('../fonts/Raleway-Light.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}
body {
background: black;
width: 100%;
overflow-x: hidden;
@ -15,6 +22,14 @@
padding: 0;
}
a:link {color:inherit}
a:active {color:inherit}
a:visited {color:inherit}
a:hover {
color:inherit;
cursor: pointer;
}
#left_button {
position: absolute;
left: 70;
@ -38,6 +53,15 @@
position: absolute;
top: 0; left: 0; bottom: 0; right: 0;
}
#report_problem {
position: fixed;
top: 10;
right: 10;
font-family: "Raleway Light", sans-serif;
text-decoration: none;
color: #ddd;
}
</style>
<script>
var handControllerImageURL = null;
@ -152,6 +176,7 @@
<a href="#" id="left_button" onmousedown="cycleLeft()"></a>
<a href="#" id="right_button" onmousedown="cycleRight()"></a>
</div>
<a href="mailto:support@highfidelity.com" id="report_problem">Report Problem</a>
</body>
</html>

View file

@ -1,7 +1,7 @@
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtWebChannel 1.0
import QtWebEngine 1.2
import QtWebEngine 1.5
import "controls"
import "controls-uit" as HifiControls
@ -13,11 +13,11 @@ Item {
id: root
HifiConstants { id: hifi }
HifiStyles.HifiConstants { id: hifistyles }
//width: parent.width
height: 600
property variant permissionsBar: {'securityOrigin':'none','feature':'none'}
property alias url: webview.url
property WebEngineView webView: webview
property bool canGoBack: webview.canGoBack
property bool canGoForward: webview.canGoForward
@ -123,5 +123,4 @@ Item {
break;
}
}
}

View file

@ -9,7 +9,7 @@
//
import QtQuick 2.5
import QtWebEngine 1.2
import QtWebEngine 1.5
WebEngineView {
id: root

View file

@ -9,10 +9,13 @@
//
import QtQuick 2.5
import QtWebEngine 1.5
AnimatedImage {
property WebEngineView webview: parent
source: "../../icons/loader-snake-64-w.gif"
visible: parent.loading && /^(http.*|)$/i.test(parent.url.toString())
visible: webview.loading && /^(http.*|)$/i.test(webview.url.toString())
playing: visible
z: 10000
anchors {
horizontalCenter: parent.horizontalCenter

View file

@ -0,0 +1,170 @@
import QtQuick 2.7
import QtWebEngine 1.5
import QtWebChannel 1.0
import QtQuick.Controls 2.2
import "../styles-uit" as StylesUIt
Flickable {
id: flick
property alias url: _webview.url
property alias canGoBack: _webview.canGoBack
property alias webViewCore: _webview
property alias webViewCoreProfile: _webview.profile
property string userScriptUrl: ""
property string urlTag: "noDownload=false";
signal newViewRequestedCallback(var request)
signal loadingChangedCallback(var loadRequest)
boundsBehavior: Flickable.StopAtBounds
StylesUIt.HifiConstants {
id: hifi
}
onHeightChanged: {
if (height > 0) {
//reload page since window dimentions changed,
//so web engine should recalculate page render dimentions
reloadTimer.start()
}
}
ScrollBar.vertical: ScrollBar {
id: scrollBar
visible: flick.contentHeight > flick.height
contentItem: Rectangle {
opacity: 0.75
implicitWidth: hifi.dimensions.scrollbarHandleWidth
radius: height / 2
color: hifi.colors.tableScrollHandleDark
}
}
function onLoadingChanged(loadRequest) {
if (WebEngineView.LoadStartedStatus === loadRequest.status) {
flick.contentWidth = flick.width
flick.contentHeight = flick.height
// Required to support clicking on "hifi://" links
var url = loadRequest.url.toString();
if (urlHandler.canHandleUrl(url)) {
if (urlHandler.handleUrl(url)) {
_webview.stop();
}
}
}
if (WebEngineView.LoadFailedStatus === loadRequest.status) {
console.log(" Tablet WebEngineView failed to load url: " + loadRequest.url.toString());
}
if (WebEngineView.LoadSucceededStatus === loadRequest.status) {
//disable Chromium's scroll bars
_webview.runJavaScript("document.body.style.overflow = 'hidden';");
//calculate page height
_webview.runJavaScript("document.body.scrollHeight;", function (i_actualPageHeight) {
if (i_actualPageHeight !== undefined) {
flick.contentHeight = i_actualPageHeight
} else {
flick.contentHeight = flick.height;
}
})
flick.contentWidth = flick.width
}
}
Timer {
id: reloadTimer
interval: 100
repeat: false
onTriggered: {
_webview.reload()
}
}
WebEngineView {
id: _webview
height: parent.height
profile: HFWebEngineProfile;
// creates a global EventBridge object.
WebEngineScript {
id: createGlobalEventBridge
sourceCode: eventBridgeJavaScriptToInject
injectionPoint: WebEngineScript.DocumentCreation
worldId: WebEngineScript.MainWorld
}
// detects when to raise and lower virtual keyboard
WebEngineScript {
id: raiseAndLowerKeyboard
injectionPoint: WebEngineScript.Deferred
sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js"
worldId: WebEngineScript.MainWorld
}
// User script.
WebEngineScript {
id: userScript
sourceUrl: flick.userScriptUrl
injectionPoint: WebEngineScript.DocumentReady // DOM ready but page load may not be finished.
worldId: WebEngineScript.MainWorld
}
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ]
property string newUrl: ""
Component.onCompleted: {
width = Qt.binding(function() { return flick.width; });
webChannel.registerObject("eventBridge", eventBridge);
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
// Ensure the JS from the web-engine makes it to our logging
_webview.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message);
});
_webview.profile.httpUserAgent = "Mozilla/5.0 Chrome (HighFidelityInterface)";
}
onFeaturePermissionRequested: {
grantFeaturePermission(securityOrigin, feature, true);
}
onContentsSizeChanged: {
flick.contentHeight = Math.max(contentsSize.height, flick.height);
flick.contentWidth = flick.width
}
//disable popup
onContextMenuRequested: {
request.accepted = true;
}
onNewViewRequested: {
newViewRequestedCallback(request)
}
onLoadingChanged: {
flick.onLoadingChanged(loadRequest)
loadingChangedCallback(loadRequest)
}
}
AnimatedImage {
//anchoring doesnt works here when changing content size
x: flick.width/2 - width/2
y: flick.height/2 - height/2
source: "../../icons/loader-snake-64-w.gif"
visible: _webview.loading && /^(http.*|)$/i.test(_webview.url.toString())
playing: visible
z: 10000
}
}

View file

@ -1,14 +1,13 @@
import QtQuick 2.5
import QtWebEngine 1.1
import QtWebChannel 1.0
import QtQuick 2.7
import "../controls-uit" as HiFiControls
Item {
property alias url: root.url
property alias scriptURL: root.userScriptUrl
property alias canGoBack: root.canGoBack;
property var goBack: root.goBack;
property alias urlTag: root.urlTag
id: root
property alias url: webroot.url
property alias scriptURL: webroot.userScriptUrl
property alias canGoBack: webroot.canGoBack;
property var goBack: webroot.webViewCore.goBack;
property alias urlTag: webroot.urlTag
property bool keyboardEnabled: true // FIXME - Keyboard HMD only: Default to false
property bool keyboardRaised: false
property bool punctuationMode: false
@ -21,84 +20,20 @@ Item {
}
*/
property alias viewProfile: root.profile
property alias viewProfile: webroot.webViewCoreProfile
WebEngineView {
id: root
objectName: "webEngineView"
x: 0
y: 0
FlickableWebViewCore {
id: webroot
width: parent.width
height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height : parent.height
profile: HFWebEngineProfile;
property string userScriptUrl: ""
// creates a global EventBridge object.
WebEngineScript {
id: createGlobalEventBridge
sourceCode: eventBridgeJavaScriptToInject
injectionPoint: WebEngineScript.DocumentCreation
worldId: WebEngineScript.MainWorld
}
// detects when to raise and lower virtual keyboard
WebEngineScript {
id: raiseAndLowerKeyboard
injectionPoint: WebEngineScript.Deferred
sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js"
worldId: WebEngineScript.MainWorld
}
// User script.
WebEngineScript {
id: userScript
sourceUrl: root.userScriptUrl
injectionPoint: WebEngineScript.DocumentReady // DOM ready but page load may not be finished.
worldId: WebEngineScript.MainWorld
}
property string urlTag: "noDownload=false";
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ]
property string newUrl: ""
Component.onCompleted: {
webChannel.registerObject("eventBridge", eventBridge);
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
// Ensure the JS from the web-engine makes it to our logging
root.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message);
});
root.profile.httpUserAgent = "Mozilla/5.0 Chrome (HighFidelityInterface)";
}
onFeaturePermissionRequested: {
grantFeaturePermission(securityOrigin, feature, true);
}
onLoadingChanged: {
onLoadingChangedCallback: {
keyboardRaised = false;
punctuationMode = false;
keyboard.resetShiftMode(false);
// Required to support clicking on "hifi://" links
if (WebEngineView.LoadStartedStatus == loadRequest.status) {
var url = loadRequest.url.toString();
url = (url.indexOf("?") >= 0) ? url + urlTag : url + "?" + urlTag;
if (urlHandler.canHandleUrl(url)) {
if (urlHandler.handleUrl(url)) {
root.stop();
}
}
}
}
onNewViewRequested:{
onNewViewRequestedCallback: {
// desktop is not defined for web-entities or tablet
if (typeof desktop !== "undefined") {
desktop.openBrowserWindow(request, profile);
@ -107,7 +42,6 @@ Item {
}
}
HiFiControls.WebSpinner { }
}
HiFiControls.Keyboard {
@ -120,5 +54,4 @@ Item {
bottom: parent.bottom
}
}
}

View file

@ -1,18 +1,14 @@
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtWebEngine 1.2
import QtWebChannel 1.0
import QtQuick 2.7
import QtWebEngine 1.5
import "../controls-uit" as HiFiControls
import "../styles" as HifiStyles
import "../styles-uit"
import "../"
import "."
Item {
id: web
id: root
HifiConstants { id: hifi }
width: parent.width
height: parent.height
width: parent !== null ? parent.width : undefined
height: parent !== null ? parent.height : undefined
property var parentStackItem: null
property int headerHeight: 70
property string url
@ -21,8 +17,8 @@ Item {
property bool keyboardRaised: false
property bool punctuationMode: false
property bool isDesktop: false
property alias webView: webview
property alias profile: webview.profile
property alias webView: web.webViewCore
property alias profile: web.webViewCoreProfile
property bool remove: false
property bool closeButtonVisible: true
@ -79,7 +75,7 @@ Item {
color: hifi.colors.baseGray
font.pixelSize: 12
verticalAlignment: Text.AlignLeft
text: webview.url
text: root.url
anchors {
top: nav.bottom
horizontalCenter: parent.horizontalCenter;
@ -104,13 +100,13 @@ Item {
function closeWebEngine() {
if (remove) {
web.destroy();
root.destroy();
return;
}
if (parentStackItem) {
parentStackItem.pop();
} else {
web.visible = false;
root.visible = false;
}
}
@ -128,67 +124,19 @@ Item {
}
function loadUrl(url) {
webview.url = url
web.url = webview.url;
web.webViewCore.url = url
root.url = web.webViewCore.url;
}
onUrlChanged: {
loadUrl(url);
}
WebEngineView {
id: webview
objectName: "webEngineView"
x: 0
y: 0
FlickableWebViewCore {
id: web
width: parent.width
height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height - web.headerHeight : parent.height - web.headerHeight
height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height - root.headerHeight : parent.height - root.headerHeight
anchors.top: buttons.bottom
profile: HFWebEngineProfile;
property string userScriptUrl: ""
// creates a global EventBridge object.
WebEngineScript {
id: createGlobalEventBridge
sourceCode: eventBridgeJavaScriptToInject
injectionPoint: WebEngineScript.DocumentCreation
worldId: WebEngineScript.MainWorld
}
// detects when to raise and lower virtual keyboard
WebEngineScript {
id: raiseAndLowerKeyboard
injectionPoint: WebEngineScript.Deferred
sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js"
worldId: WebEngineScript.MainWorld
}
// User script.
WebEngineScript {
id: userScript
sourceUrl: webview.userScriptUrl
injectionPoint: WebEngineScript.DocumentReady // DOM ready but page load may not be finished.
worldId: WebEngineScript.MainWorld
}
property string urlTag: "noDownload=false";
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ]
property string newUrl: ""
Component.onCompleted: {
webChannel.registerObject("eventBridge", eventBridge);
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
// Ensure the JS from the web-engine makes it to our logging
webview.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message);
});
}
onFeaturePermissionRequested: {
grantFeaturePermission(securityOrigin, feature, true);
}
onUrlChanged: {
// Record history, skipping null and duplicate items.
@ -201,34 +149,16 @@ Item {
}
}
onLoadingChanged: {
onLoadingChangedCallback: {
keyboardRaised = false;
punctuationMode = false;
keyboard.resetShiftMode(false);
// Required to support clicking on "hifi://" links
if (WebEngineView.LoadStartedStatus == loadRequest.status) {
var url = loadRequest.url.toString();
if (urlHandler.canHandleUrl(url)) {
if (urlHandler.handleUrl(url)) {
root.stop();
}
}
}
if (WebEngineView.LoadFailedStatus == loadRequest.status) {
console.log(" Tablet WebEngineView failed to load url: " + loadRequest.url.toString());
}
if (WebEngineView.LoadSucceededStatus == loadRequest.status) {
webview.forceActiveFocus();
}
}
onNewViewRequested: {
request.openIn(webview);
webViewCore.forceActiveFocus();
}
HiFiControls.WebSpinner { }
onNewViewRequestedCallback: {
request.openIn(webViewCore);
}
}
HiFiControls.Keyboard {
@ -244,7 +174,7 @@ Item {
}
Component.onCompleted: {
web.isDesktop = (typeof desktop !== "undefined");
root.isDesktop = (typeof desktop !== "undefined");
keyboardEnabled = HMD.active;
}

View file

@ -1,17 +1,19 @@
import QtQuick 2.5
import QtWebEngine 1.1
import QtWebChannel 1.0
import QtQuick 2.7
import "../controls-uit" as HiFiControls
Item {
property alias url: root.url
property alias scriptURL: root.userScriptUrl
property alias canGoBack: root.canGoBack;
property var goBack: root.goBack;
property alias urlTag: root.urlTag
width: parent !== null ? parent.width : undefined
height: parent !== null ? parent.height : undefined
property alias url: webroot.url
property alias scriptURL: webroot.userScriptUrl
property alias canGoBack: webroot.canGoBack;
property var goBack: webroot.webViewCore.goBack;
property alias urlTag: webroot.urlTag
property bool keyboardEnabled: true // FIXME - Keyboard HMD only: Default to false
property bool keyboardRaised: false
property bool punctuationMode: false
property alias flickable: webroot.interactive
// FIXME - Keyboard HMD only: Make Interface either set keyboardRaised property directly in OffscreenQmlSurface
// or provide HMDinfo object to QML in RenderableWebEntityItem and do the following.
@ -21,82 +23,20 @@ Item {
}
*/
property alias viewProfile: root.profile
property alias viewProfile: webroot.webViewCoreProfile
WebEngineView {
id: root
objectName: "webEngineView"
x: 0
y: 0
FlickableWebViewCore {
id: webroot
width: parent.width
height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height : parent.height
profile: HFWebEngineProfile;
property string userScriptUrl: ""
// creates a global EventBridge object.
WebEngineScript {
id: createGlobalEventBridge
sourceCode: eventBridgeJavaScriptToInject
injectionPoint: WebEngineScript.DocumentCreation
worldId: WebEngineScript.MainWorld
}
// detects when to raise and lower virtual keyboard
WebEngineScript {
id: raiseAndLowerKeyboard
injectionPoint: WebEngineScript.Deferred
sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js"
worldId: WebEngineScript.MainWorld
}
// User script.
WebEngineScript {
id: userScript
sourceUrl: root.userScriptUrl
injectionPoint: WebEngineScript.DocumentReady // DOM ready but page load may not be finished.
worldId: WebEngineScript.MainWorld
}
property string urlTag: "noDownload=false";
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ]
property string newUrl: ""
Component.onCompleted: {
webChannel.registerObject("eventBridge", eventBridge);
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
// Ensure the JS from the web-engine makes it to our logging
root.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message);
});
}
onFeaturePermissionRequested: {
grantFeaturePermission(securityOrigin, feature, true);
}
onLoadingChanged: {
onLoadingChangedCallback: {
keyboardRaised = false;
punctuationMode = false;
keyboard.resetShiftMode(false);
// Required to support clicking on "hifi://" links
if (WebEngineView.LoadStartedStatus == loadRequest.status) {
var url = loadRequest.url.toString();
url = (url.indexOf("?") >= 0) ? url + urlTag : url + "?" + urlTag;
if (urlHandler.canHandleUrl(url)) {
if (urlHandler.handleUrl(url)) {
root.stop();
}
}
}
}
onNewViewRequested:{
onNewViewRequestedCallback: {
// desktop is not defined for web-entities or tablet
if (typeof desktop !== "undefined") {
desktop.openBrowserWindow(request, profile);
@ -104,8 +44,6 @@ Item {
tabletRoot.openBrowserWindow(request, profile);
}
}
HiFiControls.WebSpinner { }
}
HiFiControls.Keyboard {
@ -118,5 +56,4 @@ Item {
bottom: parent.bottom
}
}
}

View file

@ -59,7 +59,7 @@ Rectangle {
}
onWalletAuthenticatedStatusResult: {
if (!isAuthenticated && !passphraseModal.visible) {
if (!isAuthenticated && passphraseModal && !passphraseModal.visible) {
passphraseModal.visible = true;
} else if (isAuthenticated) {
root.activeView = "walletHome";

View file

@ -1,5 +1,6 @@
import QtQuick 2.5
import QtGraphicalEffects 1.0
import QtQuick.Layouts 1.3
import "../../styles-uit"
import "../audio" as HifiAudio
@ -109,15 +110,45 @@ Item {
}
}
RalewaySemiBold {
id: usernameText
text: tabletRoot.username
anchors.verticalCenter: parent.verticalCenter
Item {
width: 150
height: 50
anchors.right: parent.right
anchors.rightMargin: 20
horizontalAlignment: Text.AlignRight
font.pixelSize: 20
color: "#afafaf"
anchors.rightMargin: 30
anchors.verticalCenter: parent.verticalCenter
ColumnLayout {
anchors.fill: parent
RalewaySemiBold {
text: Account.loggedIn ? qsTr("Log out") : qsTr("Log in")
horizontalAlignment: Text.AlignRight
anchors.right: parent.right
font.pixelSize: 20
color: "#afafaf"
}
RalewaySemiBold {
visible: Account.loggedIn
height: Account.loggedIn ? parent.height/2 - parent.spacing/2 : 0
text: Account.loggedIn ? "[" + tabletRoot.usernameShort + "]" : ""
horizontalAlignment: Text.AlignRight
anchors.right: parent.right
font.pixelSize: 20
color: "#afafaf"
}
}
MouseArea {
anchors.fill: parent
onClicked: {
if (!Account.loggedIn) {
DialogsManager.showLoginDialog()
} else {
Account.logOut()
}
}
}
}
}

View file

@ -8,6 +8,7 @@ Item {
id: tabletRoot
objectName: "tabletRoot"
property string username: "Unknown user"
property string usernameShort: "Unknown user"
property var rootMenu;
property var openModal: null;
property var openMessage: null;
@ -157,6 +158,11 @@ Item {
function setUsername(newUsername) {
username = newUsername;
usernameShort = newUsername.substring(0, 8);
if (newUsername.length > 8) {
usernameShort = usernameShort + "..."
}
}
ListModel {

View file

@ -604,6 +604,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
DependencyManager::registerInheritance<SpatialParentFinder, InterfaceParentFinder>();
// Set dependencies
DependencyManager::set<Cursor::Manager>();
DependencyManager::set<AccountManager>(std::bind(&Application::getUserAgent, qApp));
DependencyManager::set<StatTracker>();
DependencyManager::set<ScriptEngines>(ScriptEngine::CLIENT_SCRIPT);
@ -2802,35 +2803,18 @@ void Application::handleSandboxStatus(QNetworkReply* reply) {
// Get controller availability
bool hasHandControllers = false;
HandControllerType handControllerType = Vive;
if (PluginUtils::isViveControllerAvailable()) {
if (PluginUtils::isViveControllerAvailable() || PluginUtils::isOculusTouchControllerAvailable()) {
hasHandControllers = true;
handControllerType = Vive;
} else if (PluginUtils::isOculusTouchControllerAvailable()) {
hasHandControllers = true;
handControllerType = Oculus;
}
// Check tutorial content versioning
bool hasTutorialContent = contentVersion >= MIN_CONTENT_VERSION.at(handControllerType);
// Check HMD use (may be technically available without being in use)
bool hasHMD = PluginUtils::isHMDAvailable();
bool isUsingHMD = _displayPlugin->isHmd();
bool isUsingHMDAndHandControllers = hasHMD && hasHandControllers && isUsingHMD;
Setting::Handle<bool> tutorialComplete{ "tutorialComplete", false };
Setting::Handle<bool> firstRun{ Settings::firstRun, true };
const QString HIFI_SKIP_TUTORIAL_COMMAND_LINE_KEY = "--skipTutorial";
// Skips tutorial/help behavior, and does NOT clear firstRun setting.
bool skipTutorial = arguments().contains(HIFI_SKIP_TUTORIAL_COMMAND_LINE_KEY);
bool isTutorialComplete = tutorialComplete.get();
bool shouldGoToTutorial = isUsingHMDAndHandControllers && hasTutorialContent && !isTutorialComplete && !skipTutorial;
qCDebug(interfaceapp) << "HMD:" << hasHMD << ", Hand Controllers: " << hasHandControllers << ", Using HMD: " << isUsingHMDAndHandControllers;
qCDebug(interfaceapp) << "Tutorial version:" << contentVersion << ", sufficient:" << hasTutorialContent <<
", complete:" << isTutorialComplete << ", should go:" << shouldGoToTutorial;
// when --url in command line, teleport to location
const QString HIFI_URL_COMMAND_LINE_KEY = "--url";
@ -2840,58 +2824,31 @@ void Application::handleSandboxStatus(QNetworkReply* reply) {
addressLookupString = arguments().value(urlIndex + 1);
}
const QString TUTORIAL_PATH = "/tutorial_begin";
static const QString SENT_TO_TUTORIAL = "tutorial";
static const QString SENT_TO_PREVIOUS_LOCATION = "previous_location";
static const QString SENT_TO_ENTRY = "entry";
static const QString SENT_TO_SANDBOX = "sandbox";
QString sentTo;
if (shouldGoToTutorial) {
if (sandboxIsRunning) {
qCDebug(interfaceapp) << "Home sandbox appears to be running, going to Home.";
DependencyManager::get<AddressManager>()->goToLocalSandbox(TUTORIAL_PATH);
sentTo = SENT_TO_TUTORIAL;
} else {
qCDebug(interfaceapp) << "Home sandbox does not appear to be running, going to Entry.";
if (firstRun.get()) {
showHelp();
}
if (addressLookupString.isEmpty()) {
DependencyManager::get<AddressManager>()->goToEntry();
sentTo = SENT_TO_ENTRY;
} else {
DependencyManager::get<AddressManager>()->loadSettings(addressLookupString);
sentTo = SENT_TO_PREVIOUS_LOCATION;
}
}
} else {
// If this is a first run we short-circuit the address passed in
if (firstRun.get() && !skipTutorial) {
if (firstRun.get()) {
showHelp();
if (isUsingHMDAndHandControllers) {
if (sandboxIsRunning) {
qCDebug(interfaceapp) << "Home sandbox appears to be running, going to Home.";
DependencyManager::get<AddressManager>()->goToLocalSandbox();
sentTo = SENT_TO_SANDBOX;
} else {
qCDebug(interfaceapp) << "Home sandbox does not appear to be running, going to Entry.";
DependencyManager::get<AddressManager>()->goToEntry();
sentTo = SENT_TO_ENTRY;
}
if (sandboxIsRunning) {
qCDebug(interfaceapp) << "Home sandbox appears to be running, going to Home.";
DependencyManager::get<AddressManager>()->goToLocalSandbox();
sentTo = SENT_TO_SANDBOX;
} else {
qCDebug(interfaceapp) << "Home sandbox does not appear to be running, going to Entry.";
DependencyManager::get<AddressManager>()->goToEntry();
sentTo = SENT_TO_ENTRY;
}
firstRun.set(false);
} else {
qCDebug(interfaceapp) << "Not first run... going to" << qPrintable(addressLookupString.isEmpty() ? QString("previous location") : addressLookupString);
DependencyManager::get<AddressManager>()->loadSettings(addressLookupString);
sentTo = SENT_TO_PREVIOUS_LOCATION;
}
}
UserActivityLogger::getInstance().logAction("startup_sent_to", {
{ "sent_to", sentTo },
@ -2900,18 +2857,10 @@ void Application::handleSandboxStatus(QNetworkReply* reply) {
{ "has_hand_controllers", hasHandControllers },
{ "is_using_hmd", isUsingHMD },
{ "is_using_hmd_and_hand_controllers", isUsingHMDAndHandControllers },
{ "content_version", contentVersion },
{ "is_tutorial_complete", isTutorialComplete },
{ "has_tutorial_content", hasTutorialContent },
{ "should_go_to_tutorial", shouldGoToTutorial }
{ "content_version", contentVersion }
});
_connectionMonitor.init();
// After all of the constructor is completed, then set firstRun to false.
if (!skipTutorial) {
firstRun.set(false);
}
}
bool Application::importJSONFromURL(const QString& urlString) {
@ -6320,11 +6269,11 @@ bool Application::askToWearAvatarAttachmentUrl(const QString& url) {
bool Application::askToReplaceDomainContent(const QString& url) {
QString methodDetails;
const int MAX_CHARACTERS_PER_LINE = 90;
if (DependencyManager::get<NodeList>()->getThisNodeCanReplaceContent()) {
QUrl originURL { url };
if (originURL.host().endsWith(MARKETPLACE_CDN_HOSTNAME)) {
// Create a confirmation dialog when this call is made
const int MAX_CHARACTERS_PER_LINE = 90;
static const QString infoText = simpleWordWrap("Your domain's content will be replaced with a new content set. "
"If you want to save what you have now, create a backup before proceeding. For more information about backing up "
"and restoring content, visit the documentation page at: ", MAX_CHARACTERS_PER_LINE) +
@ -6360,7 +6309,9 @@ bool Application::askToReplaceDomainContent(const QString& url) {
}
} else {
methodDetails = "UserDoesNotHavePermissionToReplaceContent";
OffscreenUi::warning("Unable to replace content", "You do not have permissions to replace domain content",
static const QString warningMessage = simpleWordWrap("The domain owner must enable 'Replace Content' "
"permissions for you in this domain's server settings before you can continue.", MAX_CHARACTERS_PER_LINE);
OffscreenUi::warning("You do not have permissions to replace domain content", warningMessage,
QMessageBox::Ok, QMessageBox::Ok);
}
QJsonObject messageProperties = {

View file

@ -1912,6 +1912,17 @@ void MyAvatar::preDisplaySide(RenderArgs* renderArgs) {
const bool shouldDrawHead = shouldRenderHead(renderArgs);
if (shouldDrawHead != _prevShouldDrawHead) {
_skeletonModel->setEnableCauterization(!shouldDrawHead);
for (int i = 0; i < _attachmentData.size(); i++) {
if (_attachmentData[i].jointName.compare("Head", Qt::CaseInsensitive) == 0 ||
_attachmentData[i].jointName.compare("Neck", Qt::CaseInsensitive) == 0 ||
_attachmentData[i].jointName.compare("LeftEye", Qt::CaseInsensitive) == 0 ||
_attachmentData[i].jointName.compare("RightEye", Qt::CaseInsensitive) == 0 ||
_attachmentData[i].jointName.compare("HeadTop_End", Qt::CaseInsensitive) == 0 ||
_attachmentData[i].jointName.compare("Face", Qt::CaseInsensitive) == 0) {
_attachmentModels[i]->setVisibleInScene(shouldDrawHead, qApp->getMain3DScene());
}
}
}
_prevShouldDrawHead = shouldDrawHead;
}

View file

@ -272,6 +272,10 @@ void Wallet::setPassphrase(const QString& passphrase) {
delete _passphrase;
}
_passphrase = new QString(passphrase);
// no matter what, we now need to clear the keys as they
// need to be read using this passphrase
_publicKeys.clear();
}
// encrypt some stuff
@ -383,11 +387,25 @@ bool Wallet::walletIsAuthenticatedWithPassphrase() {
// FIXME: initialize OpenSSL elsewhere soon
initialize();
// this should always be false if we don't have a passphrase
// cached yet
if (!_passphrase || _passphrase->isEmpty()) {
return false;
}
if (_publicKeys.count() > 0) {
// we _must_ be authenticated if the publicKeys are there
return true;
}
// otherwise, we have a passphrase but no keys, so we have to check
auto publicKey = readPublicKey(keyFilePath().toStdString().c_str());
if (publicKey.size() > 0) {
if (auto key = readPrivateKey(keyFilePath().toStdString().c_str())) {
RSA_free(key);
// be sure to add the public key so we don't do this over and over
_publicKeys.push_back(publicKey.toBase64());
return true;
}
}

View file

@ -18,6 +18,8 @@ AccountScriptingInterface* AccountScriptingInterface::getInstance() {
auto accountManager = DependencyManager::get<AccountManager>();
QObject::connect(accountManager.data(), &AccountManager::profileChanged,
&sharedInstance, &AccountScriptingInterface::usernameChanged);
QObject::connect(accountManager.data(), &AccountManager::usernameChanged,
&sharedInstance, &AccountScriptingInterface::onUsernameChanged);
return &sharedInstance;
}
@ -31,6 +33,21 @@ bool AccountScriptingInterface::checkAndSignalForAccessToken() {
return accountManager->checkAndSignalForAccessToken();
}
void AccountScriptingInterface::logOut() {
auto accountManager = DependencyManager::get<AccountManager>();
return accountManager->logout();
}
AccountScriptingInterface::AccountScriptingInterface(QObject *parent): QObject(parent) {
m_loggedIn = isLoggedIn();
emit loggedInChanged(m_loggedIn);
}
void AccountScriptingInterface::onUsernameChanged(QString username) {
m_loggedIn = (username != QString());
emit loggedInChanged(m_loggedIn);
}
QString AccountScriptingInterface::getUsername() {
auto accountManager = DependencyManager::get<AccountManager>();
if (accountManager->isLoggedIn()) {

View file

@ -18,6 +18,7 @@ class AccountScriptingInterface : public QObject {
Q_OBJECT
Q_PROPERTY(QString username READ getUsername NOTIFY usernameChanged)
Q_PROPERTY(bool loggedIn READ loggedIn NOTIFY loggedInChanged)
/**jsdoc
* @namespace Account
@ -32,6 +33,7 @@ signals:
* @return {Signal}
*/
void usernameChanged();
void loggedInChanged(bool loggedIn);
public slots:
static AccountScriptingInterface* getInstance();
@ -50,6 +52,20 @@ public slots:
*/
bool isLoggedIn();
bool checkAndSignalForAccessToken();
void logOut();
public:
AccountScriptingInterface(QObject* parent = nullptr);
bool loggedIn() const {
return m_loggedIn;
}
private slots:
void onUsernameChanged(QString username);
private:
bool m_loggedIn { false };
};
#endif // hifi_AccountScriptingInterface_h

View file

@ -33,7 +33,12 @@ void DialogsManagerScriptingInterface::showAddressBar() {
void DialogsManagerScriptingInterface::hideAddressBar() {
QMetaObject::invokeMethod(DependencyManager::get<DialogsManager>().data(),
"hideAddressBar", Qt::QueuedConnection);
"hideAddressBar", Qt::QueuedConnection);
}
void DialogsManagerScriptingInterface::showLoginDialog() {
QMetaObject::invokeMethod(DependencyManager::get<DialogsManager>().data(),
"showLoginDialog", Qt::QueuedConnection);
}
void DialogsManagerScriptingInterface::showFeed() {

View file

@ -24,6 +24,7 @@ public:
public slots:
void showAddressBar();
void hideAddressBar();
void showLoginDialog();
signals:
void addressBarShown(bool visible);

View file

@ -92,6 +92,7 @@ void EntityMotionState::updateServerPhysicsVariables() {
Transform localTransform;
_entity->getLocalTransformAndVelocities(localTransform, _serverVelocity, _serverAngularVelocity);
_serverVariablesSet = true;
_serverPosition = localTransform.getTranslation();
_serverRotation = localTransform.getRotation();
_serverAcceleration = _entity->getAcceleration();
@ -99,18 +100,19 @@ void EntityMotionState::updateServerPhysicsVariables() {
}
void EntityMotionState::handleDeactivation() {
// copy _server data to entity
bool success;
_entity->setPosition(_serverPosition, success, false);
_entity->setOrientation(_serverRotation, success, false);
_entity->setVelocity(ENTITY_ITEM_ZERO_VEC3);
_entity->setAngularVelocity(ENTITY_ITEM_ZERO_VEC3);
// and also to RigidBody
btTransform worldTrans;
worldTrans.setOrigin(glmToBullet(_serverPosition));
worldTrans.setRotation(glmToBullet(_serverRotation));
_body->setWorldTransform(worldTrans);
// no need to update velocities... should already be zero
if (_serverVariablesSet) {
// copy _server data to entity
Transform localTransform = _entity->getLocalTransform();
localTransform.setTranslation(_serverPosition);
localTransform.setRotation(_serverRotation);
_entity->setLocalTransformAndVelocities(localTransform, ENTITY_ITEM_ZERO_VEC3, ENTITY_ITEM_ZERO_VEC3);
// and also to RigidBody
btTransform worldTrans;
worldTrans.setOrigin(glmToBullet(_entity->getPosition()));
worldTrans.setRotation(glmToBullet(_entity->getRotation()));
_body->setWorldTransform(worldTrans);
// no need to update velocities... should already be zero
}
}
// virtual
@ -339,6 +341,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
// if we've never checked before, our _lastStep will be 0, and we need to initialize our state
if (_lastStep == 0) {
btTransform xform = _body->getWorldTransform();
_serverVariablesSet = true;
_serverPosition = worldToLocal.transform(bulletToGLM(xform.getOrigin()));
_serverRotation = worldToLocal.getRotation() * bulletToGLM(xform.getRotation());
_serverVelocity = worldVelocityToLocal.transform(getBodyLinearVelocityGTSigma());

View file

@ -107,6 +107,7 @@ protected:
// Meanwhile we also keep a raw EntityItem* for internal stuff where the pointer is guaranteed valid.
EntityItem* _entity;
bool _serverVariablesSet { false };
glm::vec3 _serverPosition; // in simulation-frame (not world-frame)
glm::quat _serverRotation;
glm::vec3 _serverVelocity;

View file

@ -731,7 +731,7 @@ void SpatiallyNestable::setScale(float value) {
}
}
const Transform SpatiallyNestable::getLocalTransform() const {
Transform SpatiallyNestable::getLocalTransform() const {
Transform result;
_transformLock.withReadLock([&] {
result =_transform;

View file

@ -121,7 +121,7 @@ public:
virtual glm::vec3 getScale(int jointIndex) const;
// object's parent's frame
virtual const Transform getLocalTransform() const;
virtual Transform getLocalTransform() const;
virtual void setLocalTransform(const Transform& transform);
virtual glm::vec3 getLocalPosition() const;

View file

@ -24,13 +24,6 @@ namespace Cursor {
return _icon;
}
class MouseInstance : public Instance {
Source getType() const override {
return Source::MOUSE;
}
};
QMap<uint16_t, QString> Manager::ICON_NAMES {
{ Icon::SYSTEM, "SYSTEM", },
{ Icon::DEFAULT, "DEFAULT", },
@ -38,7 +31,7 @@ namespace Cursor {
{ Icon::ARROW, "ARROW", },
{ Icon::RETICLE, "RETICLE", },
};
QMap<uint16_t, QString> Manager::ICONS;
static uint16_t _customIconId = Icon::USER_BASE;
Manager::Manager() {
@ -62,8 +55,8 @@ namespace Cursor {
}
Manager& Manager::instance() {
static Manager instance;
return instance;
static QSharedPointer<Manager> instance = DependencyManager::get<Cursor::Manager>();
return *instance;
}
QList<uint16_t> Manager::registeredIcons() const {
@ -76,7 +69,6 @@ namespace Cursor {
Instance* Manager::getCursor(uint8_t index) {
Q_ASSERT(index < getCount());
static MouseInstance mouseInstance;
if (index == 0) {
return &mouseInstance;
}

View file

@ -8,6 +8,7 @@
#pragma once
#include <stdint.h>
#include <DependencyManager.h>
#include <GLMHelpers.h>
@ -39,7 +40,15 @@ namespace Cursor {
uint16_t _icon;
};
class Manager {
class MouseInstance : public Instance {
Source getType() const override {
return Source::MOUSE;
}
};
class Manager : public QObject, public Dependency {
SINGLETON_DEPENDENCY
Manager();
Manager(const Manager& other) = delete;
public:
@ -52,12 +61,13 @@ namespace Cursor {
QList<uint16_t> registeredIcons() const;
const QString& getIconImage(uint16_t icon);
static QMap<uint16_t, QString> ICONS;
static QMap<uint16_t, QString> ICON_NAMES;
static Icon lookupIcon(const QString& name);
static const QString& getIconName(const Icon& icon);
private:
MouseInstance mouseInstance;
float _scale{ 1.0f };
QMap<uint16_t, QString> ICONS;
};
}

View file

@ -134,7 +134,7 @@
if (parseInt(cost) > 0) {
var priceElement = $(this).find('.price')
priceElement.css({ "width": "auto", "padding": "3px 5px", "height": "26px" });
priceElement.text(parseFloat(cost / 100).toFixed(2) + ' HFC');
priceElement.text(cost + ' HFC');
priceElement.css({ "min-width": priceElement.width() + 10 });
}
});

View file

@ -0,0 +1,168 @@
(function () {
var FORCE_DROP_CHANNEL = "Hifi-Hand-Drop";
var proxInterval,
proxTimeout;
var _entityID;
this.preload = function (entityID) {
_entityID = entityID;
Entities.editEntity(_entityID, {
userData: '{"grabbableKey": {"grabbable": true}'
});
};
var particleTrailEntity = null;
function particleTrail() {
var props = {
type: 'ParticleEffect',
name: 'Particle',
parentID: _entityID,
isEmitting: true,
lifespan: 2.0,
maxParticles: 100,
textures: 'https://content.highfidelity.com/DomainContent/production/Particles/wispy-smoke.png',
emitRate: 50,
emitSpeed: 0,
emitterShouldTrail: true,
particleRadius: 0,
radiusSpread: 0,
radiusStart: .2,
radiusFinish: 0.1,
color: {
red: 201,
blue: 201,
green: 34
},
accelerationSpread: {
x: 0,
y: 0,
z: 0
},
alpha: 0,
alphaSpread: 0,
alphaStart: 1,
alphaFinish: 0,
polarStart: 0,
polarFinish: 0,
azimuthStart: -180,
azimuthFinish: 180
};
particleTrailEntity = Entities.addEntity(props);
}
function particleExplode() {
var entPos = Entities.getEntityProperties(_entityID, 'position').position;
var props = {
type: 'ParticleEffect',
name: 'Particle',
parentID: _entityID,
isEmitting: true,
lifespan: 2,
maxParticles: 10,
position: entPos,
textures: 'https://content.highfidelity.com/DomainContent/production/Particles/wispy-smoke.png',
emitRate: 1,
emitSpeed: 0,
emitterShouldTrail: false,
particleRadius: 1,
radiusSpread: 0,
radiusStart: 0,
radiusFinish: 1,
color: {
red: 232,
blue: 232,
green: 26
},
emitAcceleration: {
x: 0,
y: 0,
z: 0
},
alpha: 0,
alphaSpread: 0,
alphaStart: 1,
alphaFinish: .5,
polarStart: 0,
polarFinish: 0,
azimuthStart: -180,
azimuthFinish: 180
};
var explosionParticles = Entities.addEntity(props);
Entities.editEntity(_entityID, {
velocity: Vec3.ZERO,
dynamic: false
});
Script.setTimeout(function () {
Entities.deleteEntity(explosionParticles);
Entities.editEntity(_entityID, {
dynamic: true
})
}, 500);
}
function clearProxCheck() {
if (proxInterval) {
Script.clearInterval(proxInterval);
Entities.deleteEntity(particleTrailEntity);
particleTrailEntity = null;
}
if (proxTimeout) {
Script.clearTimeout(proxTimeout);
}
}
function proxCheck() {
var ballPos = Entities.getEntityProperties(_entityID, ['position']).position;
var isAnyAvatarInRange = AvatarList.isAvatarInRange(ballPos, 1);
if (isAnyAvatarInRange) {
clearProxCheck();
particleExplode();
}
}
this.startDistanceGrab = function (thisEntityID, triggerHandAndAvatarUUIDArray) {
clearProxCheck();
var triggerHand = triggerHandAndAvatarUUIDArray[0];
var avatarUUID = triggerHandAndAvatarUUIDArray[1];
var ballPos = Entities.getEntityProperties(_entityID, ['position']).position;
var MAX_DISTANCE_GRAB = 2; //meter
if (Vec3.distance(ballPos, AvatarList.getAvatar(avatarUUID).position) > MAX_DISTANCE_GRAB) {
Messages.sendMessage(FORCE_DROP_CHANNEL, triggerHand, true);
}
};
this.startNearGrab = function (thisEntityID, triggerHandAndAvatarUUIDArray) {
clearProxCheck();
};
this.releaseGrab = function (thisEntityID) {
if (particleTrailEntity === null) {
particleTrail();
}
Script.setTimeout(function () {
proxInterval = Script.setInterval(proxCheck, 50);
}, 200); // Setting a delay to give it time to leave initial avatar without proc.
proxTimeout = Script.setTimeout(function () {
clearProxCheck();
}, 10000)
};
this.collisionWithEntity = function (thisEntityID, collisionEntityID, collisionInfo) {
clearProxCheck();
};
});