mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-09 08:10:15 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into controller-dispatcher-1
This commit is contained in:
commit
15c853567d
55 changed files with 1324 additions and 907 deletions
|
@ -35,7 +35,7 @@ void ScriptableAvatar::startAnimation(const QString& url, float fps, float prior
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_animation = DependencyManager::get<AnimationCache>()->getAnimation(url);
|
_animation = DependencyManager::get<AnimationCache>()->getAnimation(url);
|
||||||
_animationDetails = AnimationDetails("", QUrl(url), fps, 0, loop, hold, false, firstFrame, lastFrame, true, firstFrame);
|
_animationDetails = AnimationDetails("", QUrl(url), fps, 0, loop, hold, false, firstFrame, lastFrame, true, firstFrame, false);
|
||||||
_maskedJoints = maskedJoints;
|
_maskedJoints = maskedJoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,14 @@
|
||||||
<title>Welcome to Interface</title>
|
<title>Welcome to Interface</title>
|
||||||
|
|
||||||
<style>
|
<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;
|
background: black;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
|
@ -15,6 +22,14 @@
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a:link {color:inherit}
|
||||||
|
a:active {color:inherit}
|
||||||
|
a:visited {color:inherit}
|
||||||
|
a:hover {
|
||||||
|
color:inherit;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
#left_button {
|
#left_button {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 70;
|
left: 70;
|
||||||
|
@ -38,6 +53,15 @@
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0; left: 0; bottom: 0; right: 0;
|
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>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
var handControllerImageURL = null;
|
var handControllerImageURL = null;
|
||||||
|
@ -152,6 +176,7 @@
|
||||||
<a href="#" id="left_button" onmousedown="cycleLeft()"></a>
|
<a href="#" id="left_button" onmousedown="cycleLeft()"></a>
|
||||||
<a href="#" id="right_button" onmousedown="cycleRight()"></a>
|
<a href="#" id="right_button" onmousedown="cycleRight()"></a>
|
||||||
</div>
|
</div>
|
||||||
|
<a href="mailto:support@highfidelity.com" id="report_problem">Report Problem</a>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 643 B |
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 909 B |
|
@ -1,7 +1,7 @@
|
||||||
import QtQuick 2.5
|
import QtQuick 2.5
|
||||||
import QtQuick.Controls 1.4
|
import QtQuick.Controls 1.4
|
||||||
import QtWebChannel 1.0
|
import QtWebChannel 1.0
|
||||||
import QtWebEngine 1.2
|
import QtWebEngine 1.5
|
||||||
|
|
||||||
import "controls"
|
import "controls"
|
||||||
import "controls-uit" as HifiControls
|
import "controls-uit" as HifiControls
|
||||||
|
@ -13,11 +13,11 @@ Item {
|
||||||
id: root
|
id: root
|
||||||
HifiConstants { id: hifi }
|
HifiConstants { id: hifi }
|
||||||
HifiStyles.HifiConstants { id: hifistyles }
|
HifiStyles.HifiConstants { id: hifistyles }
|
||||||
//width: parent.width
|
|
||||||
height: 600
|
height: 600
|
||||||
property variant permissionsBar: {'securityOrigin':'none','feature':'none'}
|
property variant permissionsBar: {'securityOrigin':'none','feature':'none'}
|
||||||
property alias url: webview.url
|
property alias url: webview.url
|
||||||
property WebEngineView webView: webview
|
|
||||||
property bool canGoBack: webview.canGoBack
|
property bool canGoBack: webview.canGoBack
|
||||||
property bool canGoForward: webview.canGoForward
|
property bool canGoForward: webview.canGoForward
|
||||||
|
|
||||||
|
@ -123,5 +123,4 @@ Item {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import QtQuick 2.5
|
import QtQuick 2.5
|
||||||
import QtWebEngine 1.2
|
import QtWebEngine 1.5
|
||||||
|
|
||||||
WebEngineView {
|
WebEngineView {
|
||||||
id: root
|
id: root
|
||||||
|
|
|
@ -9,10 +9,13 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import QtQuick 2.5
|
import QtQuick 2.5
|
||||||
|
import QtWebEngine 1.5
|
||||||
|
|
||||||
AnimatedImage {
|
AnimatedImage {
|
||||||
|
property WebEngineView webview: parent
|
||||||
source: "../../icons/loader-snake-64-w.gif"
|
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
|
z: 10000
|
||||||
anchors {
|
anchors {
|
||||||
horizontalCenter: parent.horizontalCenter
|
horizontalCenter: parent.horizontalCenter
|
||||||
|
|
170
interface/resources/qml/controls/FlickableWebViewCore.qml
Normal file
170
interface/resources/qml/controls/FlickableWebViewCore.qml
Normal 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
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,14 +1,13 @@
|
||||||
import QtQuick 2.5
|
import QtQuick 2.7
|
||||||
import QtWebEngine 1.1
|
|
||||||
import QtWebChannel 1.0
|
|
||||||
import "../controls-uit" as HiFiControls
|
import "../controls-uit" as HiFiControls
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
property alias url: root.url
|
id: root
|
||||||
property alias scriptURL: root.userScriptUrl
|
property alias url: webroot.url
|
||||||
property alias canGoBack: root.canGoBack;
|
property alias scriptURL: webroot.userScriptUrl
|
||||||
property var goBack: root.goBack;
|
property alias canGoBack: webroot.canGoBack;
|
||||||
property alias urlTag: root.urlTag
|
property var goBack: webroot.webViewCore.goBack;
|
||||||
|
property alias urlTag: webroot.urlTag
|
||||||
property bool keyboardEnabled: true // FIXME - Keyboard HMD only: Default to false
|
property bool keyboardEnabled: true // FIXME - Keyboard HMD only: Default to false
|
||||||
property bool keyboardRaised: false
|
property bool keyboardRaised: false
|
||||||
property bool punctuationMode: false
|
property bool punctuationMode: false
|
||||||
|
@ -21,84 +20,20 @@ Item {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
property alias viewProfile: root.profile
|
property alias viewProfile: webroot.webViewCoreProfile
|
||||||
|
|
||||||
WebEngineView {
|
FlickableWebViewCore {
|
||||||
id: root
|
id: webroot
|
||||||
objectName: "webEngineView"
|
|
||||||
x: 0
|
|
||||||
y: 0
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height : parent.height
|
height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height : parent.height
|
||||||
|
|
||||||
profile: HFWebEngineProfile;
|
onLoadingChangedCallback: {
|
||||||
|
|
||||||
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: {
|
|
||||||
keyboardRaised = false;
|
keyboardRaised = false;
|
||||||
punctuationMode = false;
|
punctuationMode = false;
|
||||||
keyboard.resetShiftMode(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
|
// desktop is not defined for web-entities or tablet
|
||||||
if (typeof desktop !== "undefined") {
|
if (typeof desktop !== "undefined") {
|
||||||
desktop.openBrowserWindow(request, profile);
|
desktop.openBrowserWindow(request, profile);
|
||||||
|
@ -107,7 +42,6 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HiFiControls.WebSpinner { }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HiFiControls.Keyboard {
|
HiFiControls.Keyboard {
|
||||||
|
@ -120,5 +54,4 @@ Item {
|
||||||
bottom: parent.bottom
|
bottom: parent.bottom
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,14 @@
|
||||||
import QtQuick 2.5
|
import QtQuick 2.7
|
||||||
import QtQuick.Controls 1.4
|
import QtWebEngine 1.5
|
||||||
import QtWebEngine 1.2
|
|
||||||
import QtWebChannel 1.0
|
|
||||||
import "../controls-uit" as HiFiControls
|
import "../controls-uit" as HiFiControls
|
||||||
import "../styles" as HifiStyles
|
import "../styles" as HifiStyles
|
||||||
import "../styles-uit"
|
import "../styles-uit"
|
||||||
import "../"
|
|
||||||
import "."
|
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: web
|
id: root
|
||||||
HifiConstants { id: hifi }
|
HifiConstants { id: hifi }
|
||||||
width: parent.width
|
width: parent !== null ? parent.width : undefined
|
||||||
height: parent.height
|
height: parent !== null ? parent.height : undefined
|
||||||
property var parentStackItem: null
|
property var parentStackItem: null
|
||||||
property int headerHeight: 70
|
property int headerHeight: 70
|
||||||
property string url
|
property string url
|
||||||
|
@ -21,8 +17,8 @@ Item {
|
||||||
property bool keyboardRaised: false
|
property bool keyboardRaised: false
|
||||||
property bool punctuationMode: false
|
property bool punctuationMode: false
|
||||||
property bool isDesktop: false
|
property bool isDesktop: false
|
||||||
property alias webView: webview
|
property alias webView: web.webViewCore
|
||||||
property alias profile: webview.profile
|
property alias profile: web.webViewCoreProfile
|
||||||
property bool remove: false
|
property bool remove: false
|
||||||
property bool closeButtonVisible: true
|
property bool closeButtonVisible: true
|
||||||
|
|
||||||
|
@ -79,7 +75,7 @@ Item {
|
||||||
color: hifi.colors.baseGray
|
color: hifi.colors.baseGray
|
||||||
font.pixelSize: 12
|
font.pixelSize: 12
|
||||||
verticalAlignment: Text.AlignLeft
|
verticalAlignment: Text.AlignLeft
|
||||||
text: webview.url
|
text: root.url
|
||||||
anchors {
|
anchors {
|
||||||
top: nav.bottom
|
top: nav.bottom
|
||||||
horizontalCenter: parent.horizontalCenter;
|
horizontalCenter: parent.horizontalCenter;
|
||||||
|
@ -104,13 +100,13 @@ Item {
|
||||||
|
|
||||||
function closeWebEngine() {
|
function closeWebEngine() {
|
||||||
if (remove) {
|
if (remove) {
|
||||||
web.destroy();
|
root.destroy();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (parentStackItem) {
|
if (parentStackItem) {
|
||||||
parentStackItem.pop();
|
parentStackItem.pop();
|
||||||
} else {
|
} else {
|
||||||
web.visible = false;
|
root.visible = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,67 +124,19 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadUrl(url) {
|
function loadUrl(url) {
|
||||||
webview.url = url
|
web.webViewCore.url = url
|
||||||
web.url = webview.url;
|
root.url = web.webViewCore.url;
|
||||||
}
|
}
|
||||||
|
|
||||||
onUrlChanged: {
|
onUrlChanged: {
|
||||||
loadUrl(url);
|
loadUrl(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
WebEngineView {
|
FlickableWebViewCore {
|
||||||
id: webview
|
id: web
|
||||||
objectName: "webEngineView"
|
|
||||||
x: 0
|
|
||||||
y: 0
|
|
||||||
width: parent.width
|
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
|
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: {
|
onUrlChanged: {
|
||||||
// Record history, skipping null and duplicate items.
|
// Record history, skipping null and duplicate items.
|
||||||
|
@ -201,34 +149,16 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onLoadingChanged: {
|
onLoadingChangedCallback: {
|
||||||
keyboardRaised = false;
|
keyboardRaised = false;
|
||||||
punctuationMode = false;
|
punctuationMode = false;
|
||||||
keyboard.resetShiftMode(false);
|
keyboard.resetShiftMode(false);
|
||||||
// Required to support clicking on "hifi://" links
|
webViewCore.forceActiveFocus();
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HiFiControls.WebSpinner { }
|
onNewViewRequestedCallback: {
|
||||||
|
request.openIn(webViewCore);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HiFiControls.Keyboard {
|
HiFiControls.Keyboard {
|
||||||
|
@ -244,7 +174,7 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
web.isDesktop = (typeof desktop !== "undefined");
|
root.isDesktop = (typeof desktop !== "undefined");
|
||||||
keyboardEnabled = HMD.active;
|
keyboardEnabled = HMD.active;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,19 @@
|
||||||
import QtQuick 2.5
|
import QtQuick 2.7
|
||||||
import QtWebEngine 1.1
|
|
||||||
import QtWebChannel 1.0
|
|
||||||
import "../controls-uit" as HiFiControls
|
import "../controls-uit" as HiFiControls
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
property alias url: root.url
|
width: parent !== null ? parent.width : undefined
|
||||||
property alias scriptURL: root.userScriptUrl
|
height: parent !== null ? parent.height : undefined
|
||||||
property alias canGoBack: root.canGoBack;
|
|
||||||
property var goBack: root.goBack;
|
property alias url: webroot.url
|
||||||
property alias urlTag: root.urlTag
|
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 keyboardEnabled: true // FIXME - Keyboard HMD only: Default to false
|
||||||
property bool keyboardRaised: false
|
property bool keyboardRaised: false
|
||||||
property bool punctuationMode: false
|
property bool punctuationMode: false
|
||||||
|
property alias flickable: webroot.interactive
|
||||||
|
|
||||||
// FIXME - Keyboard HMD only: Make Interface either set keyboardRaised property directly in OffscreenQmlSurface
|
// 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.
|
// 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 {
|
FlickableWebViewCore {
|
||||||
id: root
|
id: webroot
|
||||||
objectName: "webEngineView"
|
|
||||||
x: 0
|
|
||||||
y: 0
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height : parent.height
|
height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height : parent.height
|
||||||
|
|
||||||
profile: HFWebEngineProfile;
|
onLoadingChangedCallback: {
|
||||||
|
|
||||||
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: {
|
|
||||||
keyboardRaised = false;
|
keyboardRaised = false;
|
||||||
punctuationMode = false;
|
punctuationMode = false;
|
||||||
keyboard.resetShiftMode(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
|
// desktop is not defined for web-entities or tablet
|
||||||
if (typeof desktop !== "undefined") {
|
if (typeof desktop !== "undefined") {
|
||||||
desktop.openBrowserWindow(request, profile);
|
desktop.openBrowserWindow(request, profile);
|
||||||
|
@ -104,8 +44,6 @@ Item {
|
||||||
tabletRoot.openBrowserWindow(request, profile);
|
tabletRoot.openBrowserWindow(request, profile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HiFiControls.WebSpinner { }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HiFiControls.Keyboard {
|
HiFiControls.Keyboard {
|
||||||
|
@ -118,5 +56,4 @@ Item {
|
||||||
bottom: parent.bottom
|
bottom: parent.bottom
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,6 @@ Rectangle {
|
||||||
property bool purchasesReceived: false;
|
property bool purchasesReceived: false;
|
||||||
property bool balanceReceived: false;
|
property bool balanceReceived: false;
|
||||||
property bool securityImageResultReceived: false;
|
property bool securityImageResultReceived: false;
|
||||||
property bool keyFilePathIfExistsResultReceived: false;
|
|
||||||
property string itemId: "";
|
property string itemId: "";
|
||||||
property string itemHref: "";
|
property string itemHref: "";
|
||||||
property double balanceAfterPurchase: 0;
|
property double balanceAfterPurchase: 0;
|
||||||
|
@ -46,10 +45,15 @@ Rectangle {
|
||||||
root.activeView = "needsLogIn";
|
root.activeView = "needsLogIn";
|
||||||
} else if (isLoggedIn) {
|
} else if (isLoggedIn) {
|
||||||
root.activeView = "initialize";
|
root.activeView = "initialize";
|
||||||
commerce.getSecurityImage();
|
|
||||||
commerce.getKeyFilePathIfExists();
|
commerce.getKeyFilePathIfExists();
|
||||||
commerce.balance();
|
}
|
||||||
commerce.inventory();
|
}
|
||||||
|
|
||||||
|
onKeyFilePathIfExistsResult: {
|
||||||
|
if (path === "" && root.activeView !== "notSetUp") {
|
||||||
|
root.activeView = "notSetUp";
|
||||||
|
} else if (path !== "" && root.activeView === "initialize") {
|
||||||
|
commerce.getSecurityImage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,8 +61,8 @@ Rectangle {
|
||||||
securityImageResultReceived = true;
|
securityImageResultReceived = true;
|
||||||
if (!exists && root.activeView !== "notSetUp") { // "If security image is not set up"
|
if (!exists && root.activeView !== "notSetUp") { // "If security image is not set up"
|
||||||
root.activeView = "notSetUp";
|
root.activeView = "notSetUp";
|
||||||
} else if (root.securityImageResultReceived && exists && root.keyFilePathIfExistsResultReceived && root.activeView === "initialize") {
|
} else if (exists && root.activeView === "initialize") {
|
||||||
root.activeView = "checkoutMain";
|
commerce.getWalletAuthenticatedStatus();
|
||||||
} else if (exists) {
|
} else if (exists) {
|
||||||
// just set the source again (to be sure the change was noticed)
|
// just set the source again (to be sure the change was noticed)
|
||||||
securityImage.source = "";
|
securityImage.source = "";
|
||||||
|
@ -66,12 +70,17 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onKeyFilePathIfExistsResult: {
|
onWalletAuthenticatedStatusResult: {
|
||||||
keyFilePathIfExistsResultReceived = true;
|
if (!isAuthenticated && !passphraseModal.visible) {
|
||||||
if (path === "" && root.activeView !== "notSetUp") {
|
passphraseModal.visible = true;
|
||||||
root.activeView = "notSetUp";
|
} else if (isAuthenticated) {
|
||||||
} else if (root.securityImageResultReceived && root.keyFilePathIfExistsResultReceived && path !== "" && root.activeView === "initialize") {
|
|
||||||
root.activeView = "checkoutMain";
|
root.activeView = "checkoutMain";
|
||||||
|
if (!balanceReceived) {
|
||||||
|
commerce.balance();
|
||||||
|
}
|
||||||
|
if (!purchasesReceived) {
|
||||||
|
commerce.inventory();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,8 +98,8 @@ Rectangle {
|
||||||
console.log("Failed to get balance", result.data.message);
|
console.log("Failed to get balance", result.data.message);
|
||||||
} else {
|
} else {
|
||||||
root.balanceReceived = true;
|
root.balanceReceived = true;
|
||||||
hfcBalanceText.text = (parseFloat(result.data.balance/100).toFixed(2)) + " HFC";
|
hfcBalanceText.text = result.data.balance + " HFC";
|
||||||
balanceAfterPurchase = parseFloat(result.data.balance/100) - root.itemPriceFull/100;
|
balanceAfterPurchase = result.data.balance - root.itemPriceFull;
|
||||||
root.setBuyText();
|
root.setBuyText();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,10 +119,6 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HifiWallet.SecurityImageModel {
|
|
||||||
id: securityImageModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// TITLE BAR START
|
// TITLE BAR START
|
||||||
//
|
//
|
||||||
|
@ -195,7 +200,6 @@ Rectangle {
|
||||||
securityImageResultReceived = false;
|
securityImageResultReceived = false;
|
||||||
purchasesReceived = false;
|
purchasesReceived = false;
|
||||||
balanceReceived = false;
|
balanceReceived = false;
|
||||||
keyFilePathIfExistsResultReceived = false;
|
|
||||||
commerce.getLoginStatus();
|
commerce.getLoginStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -221,7 +225,20 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HifiWallet.PassphraseModal {
|
||||||
|
id: passphraseModal;
|
||||||
|
visible: false;
|
||||||
|
anchors.top: titleBarContainer.bottom;
|
||||||
|
anchors.bottom: parent.bottom;
|
||||||
|
anchors.left: parent.left;
|
||||||
|
anchors.right: parent.right;
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
onSendSignalToParent: {
|
||||||
|
sendToScript(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// "WALLET NOT SET UP" START
|
// "WALLET NOT SET UP" START
|
||||||
|
@ -553,7 +570,7 @@ Rectangle {
|
||||||
}
|
}
|
||||||
RalewayRegular {
|
RalewayRegular {
|
||||||
id: balanceAfterPurchaseText;
|
id: balanceAfterPurchaseText;
|
||||||
text: balanceAfterPurchase.toFixed(2) + " HFC";
|
text: balanceAfterPurchase + " HFC";
|
||||||
// Text size
|
// Text size
|
||||||
size: balanceAfterPurchaseTextLabel.size;
|
size: balanceAfterPurchaseTextLabel.size;
|
||||||
// Anchors
|
// Anchors
|
||||||
|
@ -648,7 +665,7 @@ Rectangle {
|
||||||
sendToScript({method: 'checkout_goToPurchases'});
|
sendToScript({method: 'checkout_goToPurchases'});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RalewayRegular {
|
RalewayRegular {
|
||||||
id: buyText;
|
id: buyText;
|
||||||
// Text size
|
// Text size
|
||||||
|
@ -687,7 +704,7 @@ Rectangle {
|
||||||
anchors.bottom: root.bottom;
|
anchors.bottom: root.bottom;
|
||||||
anchors.left: parent.left;
|
anchors.left: parent.left;
|
||||||
anchors.right: parent.right;
|
anchors.right: parent.right;
|
||||||
|
|
||||||
RalewayRegular {
|
RalewayRegular {
|
||||||
id: completeText;
|
id: completeText;
|
||||||
text: "<b>Purchase Complete!</b><br><br>You bought <b>" + (itemNameText.text) + "</b> by <b>" + (itemAuthorText.text) + "</b>";
|
text: "<b>Purchase Complete!</b><br><br>You bought <b>" + (itemNameText.text) + "</b> by <b>" + (itemAuthorText.text) + "</b>";
|
||||||
|
@ -706,7 +723,7 @@ Rectangle {
|
||||||
horizontalAlignment: Text.AlignHCenter;
|
horizontalAlignment: Text.AlignHCenter;
|
||||||
verticalAlignment: Text.AlignVCenter;
|
verticalAlignment: Text.AlignVCenter;
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: checkoutSuccessActionButtonsContainer;
|
id: checkoutSuccessActionButtonsContainer;
|
||||||
// Size
|
// Size
|
||||||
|
@ -756,7 +773,7 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: continueShoppingButtonContainer;
|
id: continueShoppingButtonContainer;
|
||||||
// Size
|
// Size
|
||||||
|
@ -799,7 +816,7 @@ Rectangle {
|
||||||
anchors.bottom: root.bottom;
|
anchors.bottom: root.bottom;
|
||||||
anchors.left: parent.left;
|
anchors.left: parent.left;
|
||||||
anchors.right: parent.right;
|
anchors.right: parent.right;
|
||||||
|
|
||||||
RalewayRegular {
|
RalewayRegular {
|
||||||
id: failureHeaderText;
|
id: failureHeaderText;
|
||||||
text: "<b>Purchase Failed.</b><br>Your Purchases and HFC balance haven't changed.";
|
text: "<b>Purchase Failed.</b><br>Your Purchases and HFC balance haven't changed.";
|
||||||
|
@ -818,7 +835,7 @@ Rectangle {
|
||||||
horizontalAlignment: Text.AlignHCenter;
|
horizontalAlignment: Text.AlignHCenter;
|
||||||
verticalAlignment: Text.AlignVCenter;
|
verticalAlignment: Text.AlignVCenter;
|
||||||
}
|
}
|
||||||
|
|
||||||
RalewayRegular {
|
RalewayRegular {
|
||||||
id: failureErrorText;
|
id: failureErrorText;
|
||||||
// Text size
|
// Text size
|
||||||
|
@ -836,7 +853,7 @@ Rectangle {
|
||||||
horizontalAlignment: Text.AlignHCenter;
|
horizontalAlignment: Text.AlignHCenter;
|
||||||
verticalAlignment: Text.AlignVCenter;
|
verticalAlignment: Text.AlignVCenter;
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: backToMarketplaceButtonContainer;
|
id: backToMarketplaceButtonContainer;
|
||||||
// Size
|
// Size
|
||||||
|
@ -892,7 +909,7 @@ Rectangle {
|
||||||
itemNameText.text = message.params.itemName;
|
itemNameText.text = message.params.itemName;
|
||||||
itemAuthorText.text = message.params.itemAuthor;
|
itemAuthorText.text = message.params.itemAuthor;
|
||||||
root.itemPriceFull = message.params.itemPrice;
|
root.itemPriceFull = message.params.itemPrice;
|
||||||
itemPriceText.text = root.itemPriceFull === 0 ? "Free" : "<b>" + (parseFloat(root.itemPriceFull/100).toFixed(2)) + " HFC</b>";
|
itemPriceText.text = root.itemPriceFull === 0 ? "Free" : "<b>" + root.itemPriceFull + " HFC</b>";
|
||||||
itemHref = message.params.itemHref;
|
itemHref = message.params.itemHref;
|
||||||
if (itemHref.indexOf('.json') === -1) {
|
if (itemHref.indexOf('.json') === -1) {
|
||||||
root.itemIsJson = false;
|
root.itemIsJson = false;
|
||||||
|
|
|
@ -28,7 +28,6 @@ Rectangle {
|
||||||
property string activeView: "initialize";
|
property string activeView: "initialize";
|
||||||
property string referrerURL: "";
|
property string referrerURL: "";
|
||||||
property bool securityImageResultReceived: false;
|
property bool securityImageResultReceived: false;
|
||||||
property bool keyFilePathIfExistsResultReceived: false;
|
|
||||||
property bool purchasesReceived: false;
|
property bool purchasesReceived: false;
|
||||||
property bool punctuationMode: false;
|
property bool punctuationMode: false;
|
||||||
// Style
|
// Style
|
||||||
|
@ -41,9 +40,15 @@ Rectangle {
|
||||||
root.activeView = "needsLogIn";
|
root.activeView = "needsLogIn";
|
||||||
} else if (isLoggedIn) {
|
} else if (isLoggedIn) {
|
||||||
root.activeView = "initialize";
|
root.activeView = "initialize";
|
||||||
commerce.getSecurityImage();
|
|
||||||
commerce.getKeyFilePathIfExists();
|
commerce.getKeyFilePathIfExists();
|
||||||
commerce.inventory();
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeyFilePathIfExistsResult: {
|
||||||
|
if (path === "" && root.activeView !== "notSetUp") {
|
||||||
|
root.activeView = "notSetUp";
|
||||||
|
} else if (path !== "" && root.activeView === "initialize") {
|
||||||
|
commerce.getSecurityImage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,8 +56,8 @@ Rectangle {
|
||||||
securityImageResultReceived = true;
|
securityImageResultReceived = true;
|
||||||
if (!exists && root.activeView !== "notSetUp") { // "If security image is not set up"
|
if (!exists && root.activeView !== "notSetUp") { // "If security image is not set up"
|
||||||
root.activeView = "notSetUp";
|
root.activeView = "notSetUp";
|
||||||
} else if (root.securityImageResultReceived && exists && root.keyFilePathIfExistsResultReceived && root.activeView === "initialize") {
|
} else if (exists && root.activeView === "initialize") {
|
||||||
root.activeView = "purchasesMain";
|
commerce.getWalletAuthenticatedStatus();
|
||||||
} else if (exists) {
|
} else if (exists) {
|
||||||
// just set the source again (to be sure the change was noticed)
|
// just set the source again (to be sure the change was noticed)
|
||||||
securityImage.source = "";
|
securityImage.source = "";
|
||||||
|
@ -60,12 +65,12 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onKeyFilePathIfExistsResult: {
|
onWalletAuthenticatedStatusResult: {
|
||||||
keyFilePathIfExistsResultReceived = true;
|
if (!isAuthenticated && !passphraseModal.visible) {
|
||||||
if (path === "" && root.activeView !== "notSetUp") {
|
passphraseModal.visible = true;
|
||||||
root.activeView = "notSetUp";
|
} else if (isAuthenticated) {
|
||||||
} else if (root.securityImageResultReceived && root.keyFilePathIfExistsResultReceived && path !== "" && root.activeView === "initialize") {
|
|
||||||
root.activeView = "purchasesMain";
|
root.activeView = "purchasesMain";
|
||||||
|
commerce.inventory();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,7 +171,6 @@ Rectangle {
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
securityImageResultReceived = false;
|
securityImageResultReceived = false;
|
||||||
purchasesReceived = false;
|
purchasesReceived = false;
|
||||||
keyFilePathIfExistsResultReceived = false;
|
|
||||||
commerce.getLoginStatus();
|
commerce.getLoginStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,6 +195,21 @@ Rectangle {
|
||||||
commerce.getLoginStatus();
|
commerce.getLoginStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HifiWallet.PassphraseModal {
|
||||||
|
id: passphraseModal;
|
||||||
|
visible: false;
|
||||||
|
anchors.top: titleBarContainer.bottom;
|
||||||
|
anchors.bottom: parent.bottom;
|
||||||
|
anchors.left: parent.left;
|
||||||
|
anchors.right: parent.right;
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
onSendSignalToParent: {
|
||||||
|
sendToScript(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// "WALLET NOT SET UP" START
|
// "WALLET NOT SET UP" START
|
||||||
|
|
|
@ -47,11 +47,26 @@ Item {
|
||||||
HifiControlsUit.Button {
|
HifiControlsUit.Button {
|
||||||
color: hifi.buttons.black;
|
color: hifi.buttons.black;
|
||||||
colorScheme: hifi.colorSchemes.dark;
|
colorScheme: hifi.colorSchemes.dark;
|
||||||
anchors.bottom: helpText.bottom;
|
anchors.bottom: resetButton.top;
|
||||||
|
anchors.bottomMargin: 15;
|
||||||
anchors.horizontalCenter: parent.horizontalCenter;
|
anchors.horizontalCenter: parent.horizontalCenter;
|
||||||
height: 50;
|
height: 50;
|
||||||
width: 250;
|
width: 250;
|
||||||
text: "Testing: Reset Wallet!";
|
text: "DEBUG: Clear Cached Passphrase";
|
||||||
|
onClicked: {
|
||||||
|
commerce.setPassphrase("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HifiControlsUit.Button {
|
||||||
|
id: resetButton;
|
||||||
|
color: hifi.buttons.red;
|
||||||
|
colorScheme: hifi.colorSchemes.dark;
|
||||||
|
anchors.bottom: helpText.bottom;
|
||||||
|
anchors.bottomMargin: 15;
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter;
|
||||||
|
height: 50;
|
||||||
|
width: 250;
|
||||||
|
text: "DEBUG: Reset Wallet!";
|
||||||
onClicked: {
|
onClicked: {
|
||||||
commerce.reset();
|
commerce.reset();
|
||||||
sendSignalToWallet({method: 'walletReset'});
|
sendSignalToWallet({method: 'walletReset'});
|
||||||
|
|
304
interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml
Normal file
304
interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml
Normal file
|
@ -0,0 +1,304 @@
|
||||||
|
//
|
||||||
|
// PassphraseModal.qml
|
||||||
|
// qml/hifi/commerce/wallet
|
||||||
|
//
|
||||||
|
// PassphraseModal
|
||||||
|
//
|
||||||
|
// Created by Zach Fox on 2017-08-31
|
||||||
|
// 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 Hifi 1.0 as Hifi
|
||||||
|
import QtQuick 2.5
|
||||||
|
import QtQuick.Controls 1.4
|
||||||
|
import "../../../styles-uit"
|
||||||
|
import "../../../controls-uit" as HifiControlsUit
|
||||||
|
import "../../../controls" as HifiControls
|
||||||
|
|
||||||
|
// references XXX from root context
|
||||||
|
|
||||||
|
Item {
|
||||||
|
HifiConstants { id: hifi; }
|
||||||
|
|
||||||
|
id: root;
|
||||||
|
z: 998;
|
||||||
|
property bool keyboardRaised: false;
|
||||||
|
|
||||||
|
Hifi.QmlCommerce {
|
||||||
|
id: commerce;
|
||||||
|
|
||||||
|
onSecurityImageResult: {
|
||||||
|
passphraseModalSecurityImage.source = "";
|
||||||
|
passphraseModalSecurityImage.source = "image://security/securityImage";
|
||||||
|
}
|
||||||
|
|
||||||
|
onWalletAuthenticatedStatusResult: {
|
||||||
|
submitPassphraseInputButton.enabled = true;
|
||||||
|
if (!isAuthenticated) {
|
||||||
|
errorText.text = "Authentication failed - please try again.";
|
||||||
|
} else {
|
||||||
|
root.visible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This object is always used in a popup.
|
||||||
|
// This MouseArea is used to prevent a user from being
|
||||||
|
// able to click on a button/mouseArea underneath the popup.
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent;
|
||||||
|
propagateComposedEvents: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This will cause a bug -- if you bring up passphrase selection in HUD mode while
|
||||||
|
// in HMD while having HMD preview enabled, then move, then finish passphrase selection,
|
||||||
|
// HMD preview will stay off.
|
||||||
|
// TODO: Fix this unlikely bug
|
||||||
|
onVisibleChanged: {
|
||||||
|
if (visible) {
|
||||||
|
passphraseField.focus = true;
|
||||||
|
sendSignalToParent({method: 'disableHmdPreview'});
|
||||||
|
} else {
|
||||||
|
sendSignalToParent({method: 'maybeEnableHmdPreview'});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Background rectangle
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent;
|
||||||
|
color: "black";
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.top: parent.top;
|
||||||
|
anchors.left: parent.left;
|
||||||
|
anchors.right: parent.right;
|
||||||
|
height: 250;
|
||||||
|
color: hifi.colors.baseGray;
|
||||||
|
|
||||||
|
RalewaySemiBold {
|
||||||
|
id: instructionsText;
|
||||||
|
text: "Enter Wallet Passphrase";
|
||||||
|
size: 16;
|
||||||
|
anchors.top: parent.top;
|
||||||
|
anchors.topMargin: 30;
|
||||||
|
anchors.left: parent.left;
|
||||||
|
anchors.leftMargin: 16;
|
||||||
|
width: passphraseField.width;
|
||||||
|
height: paintedHeight;
|
||||||
|
// Style
|
||||||
|
color: hifi.colors.faintGray;
|
||||||
|
// Alignment
|
||||||
|
horizontalAlignment: Text.AlignLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
HifiControlsUit.TextField {
|
||||||
|
id: passphraseField;
|
||||||
|
anchors.top: instructionsText.bottom;
|
||||||
|
anchors.topMargin: 4;
|
||||||
|
anchors.left: instructionsText.left;
|
||||||
|
width: 280;
|
||||||
|
height: 50;
|
||||||
|
echoMode: TextInput.Password;
|
||||||
|
placeholderText: "passphrase";
|
||||||
|
|
||||||
|
onFocusChanged: {
|
||||||
|
root.keyboardRaised = focus;
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent;
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
parent.focus = true;
|
||||||
|
root.keyboardRaised = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onAccepted: {
|
||||||
|
submitPassphraseInputButton.enabled = false;
|
||||||
|
commerce.setPassphrase(passphraseField.text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show passphrase text
|
||||||
|
HifiControlsUit.CheckBox {
|
||||||
|
id: showPassphrase;
|
||||||
|
colorScheme: hifi.colorSchemes.dark;
|
||||||
|
anchors.left: passphraseField.left;
|
||||||
|
anchors.top: passphraseField.bottom;
|
||||||
|
anchors.topMargin: 8;
|
||||||
|
height: 30;
|
||||||
|
text: "Show passphrase as plain text";
|
||||||
|
boxSize: 24;
|
||||||
|
onClicked: {
|
||||||
|
passphraseField.echoMode = checked ? TextInput.Normal : TextInput.Password;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Security Image
|
||||||
|
Item {
|
||||||
|
id: securityImageContainer;
|
||||||
|
// Anchors
|
||||||
|
anchors.top: instructionsText.top;
|
||||||
|
anchors.left: passphraseField.right;
|
||||||
|
anchors.leftMargin: 12;
|
||||||
|
anchors.right: parent.right;
|
||||||
|
Image {
|
||||||
|
id: passphraseModalSecurityImage;
|
||||||
|
anchors.top: parent.top;
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter;
|
||||||
|
height: 75;
|
||||||
|
width: height;
|
||||||
|
fillMode: Image.PreserveAspectFit;
|
||||||
|
mipmap: true;
|
||||||
|
source: "image://security/securityImage";
|
||||||
|
cache: false;
|
||||||
|
onVisibleChanged: {
|
||||||
|
commerce.getSecurityImage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Image {
|
||||||
|
id: passphraseModalSecurityImageOverlay;
|
||||||
|
source: "images/lockOverlay.png";
|
||||||
|
width: passphraseModalSecurityImage.width * 0.45;
|
||||||
|
height: passphraseModalSecurityImage.height * 0.45;
|
||||||
|
anchors.bottom: passphraseModalSecurityImage.bottom;
|
||||||
|
anchors.right: passphraseModalSecurityImage.right;
|
||||||
|
mipmap: true;
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
// "Security image" text below pic
|
||||||
|
RalewayRegular {
|
||||||
|
text: "security image";
|
||||||
|
// Text size
|
||||||
|
size: 12;
|
||||||
|
// Anchors
|
||||||
|
anchors.top: passphraseModalSecurityImage.bottom;
|
||||||
|
anchors.topMargin: 4;
|
||||||
|
anchors.left: securityImageContainer.left;
|
||||||
|
anchors.right: securityImageContainer.right;
|
||||||
|
height: paintedHeight;
|
||||||
|
// Style
|
||||||
|
color: hifi.colors.faintGray;
|
||||||
|
// Alignment
|
||||||
|
horizontalAlignment: Text.AlignHCenter;
|
||||||
|
verticalAlignment: Text.AlignVCenter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error text above buttons
|
||||||
|
RalewaySemiBold {
|
||||||
|
id: errorText;
|
||||||
|
text: "";
|
||||||
|
// Text size
|
||||||
|
size: 16;
|
||||||
|
// Anchors
|
||||||
|
anchors.bottom: passphrasePopupActionButtonsContainer.top;
|
||||||
|
anchors.bottomMargin: 4;
|
||||||
|
anchors.left: parent.left;
|
||||||
|
anchors.leftMargin: 16;
|
||||||
|
anchors.right: parent.right;
|
||||||
|
anchors.rightMargin: 16;
|
||||||
|
height: 30;
|
||||||
|
// Style
|
||||||
|
color: hifi.colors.redHighlight;
|
||||||
|
// Alignment
|
||||||
|
horizontalAlignment: Text.AlignHCenter;
|
||||||
|
verticalAlignment: Text.AlignVCenter;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// ACTION BUTTONS START
|
||||||
|
//
|
||||||
|
Item {
|
||||||
|
id: passphrasePopupActionButtonsContainer;
|
||||||
|
// Size
|
||||||
|
width: root.width;
|
||||||
|
height: 50;
|
||||||
|
// Anchors
|
||||||
|
anchors.left: parent.left;
|
||||||
|
anchors.bottom: parent.bottom;
|
||||||
|
anchors.bottomMargin: 10;
|
||||||
|
|
||||||
|
// "Cancel" button
|
||||||
|
HifiControlsUit.Button {
|
||||||
|
id: cancelPassphraseInputButton;
|
||||||
|
color: hifi.buttons.black;
|
||||||
|
colorScheme: hifi.colorSchemes.dark;
|
||||||
|
anchors.top: parent.top;
|
||||||
|
height: 40;
|
||||||
|
anchors.left: parent.left;
|
||||||
|
anchors.leftMargin: 20;
|
||||||
|
width: parent.width/2 - anchors.leftMargin*2;
|
||||||
|
text: "Cancel"
|
||||||
|
onClicked: {
|
||||||
|
sendSignalToParent({method: 'passphrasePopup_cancelClicked'});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// "Submit" button
|
||||||
|
HifiControlsUit.Button {
|
||||||
|
id: submitPassphraseInputButton;
|
||||||
|
color: hifi.buttons.blue;
|
||||||
|
colorScheme: hifi.colorSchemes.dark;
|
||||||
|
anchors.top: parent.top;
|
||||||
|
height: 40;
|
||||||
|
anchors.right: parent.right;
|
||||||
|
anchors.rightMargin: 20;
|
||||||
|
width: parent.width/2 - anchors.rightMargin*2;
|
||||||
|
text: "Submit"
|
||||||
|
onClicked: {
|
||||||
|
submitPassphraseInputButton.enabled = false;
|
||||||
|
commerce.setPassphrase(passphraseField.text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: keyboardContainer;
|
||||||
|
z: 999;
|
||||||
|
visible: keyboard.raised;
|
||||||
|
property bool punctuationMode: false;
|
||||||
|
anchors {
|
||||||
|
bottom: parent.bottom;
|
||||||
|
left: parent.left;
|
||||||
|
right: parent.right;
|
||||||
|
}
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: lowerKeyboardButton;
|
||||||
|
source: "images/lowerKeyboard.png";
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter;
|
||||||
|
anchors.bottom: keyboard.top;
|
||||||
|
height: 30;
|
||||||
|
width: 120;
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent;
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
root.keyboardRaised = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HifiControlsUit.Keyboard {
|
||||||
|
id: keyboard;
|
||||||
|
raised: HMD.mounted && root.keyboardRaised;
|
||||||
|
numeric: parent.punctuationMode;
|
||||||
|
anchors {
|
||||||
|
bottom: parent.bottom;
|
||||||
|
left: parent.left;
|
||||||
|
right: parent.right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
signal sendSignalToParent(var msg);
|
||||||
|
}
|
|
@ -40,8 +40,8 @@ Item {
|
||||||
passphrasePageSecurityImage.source = "image://security/securityImage";
|
passphrasePageSecurityImage.source = "image://security/securityImage";
|
||||||
}
|
}
|
||||||
|
|
||||||
onPassphraseSetupStatusResult: {
|
onWalletAuthenticatedStatusResult: {
|
||||||
sendMessageToLightbox({method: 'statusResult', status: passphraseIsSetup});
|
sendMessageToLightbox({method: 'statusResult', status: isAuthenticated});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,10 +58,6 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SecurityImageModel {
|
|
||||||
id: gridModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
HifiControlsUit.TextField {
|
HifiControlsUit.TextField {
|
||||||
id: passphraseField;
|
id: passphraseField;
|
||||||
anchors.top: parent.top;
|
anchors.top: parent.top;
|
||||||
|
@ -199,7 +195,7 @@ Item {
|
||||||
// Text below TextFields
|
// Text below TextFields
|
||||||
RalewaySemiBold {
|
RalewaySemiBold {
|
||||||
id: passwordReqs;
|
id: passwordReqs;
|
||||||
text: "Passphrase must be at least 4 characters";
|
text: "Passphrase must be at least 3 characters";
|
||||||
// Text size
|
// Text size
|
||||||
size: 16;
|
size: 16;
|
||||||
// Anchors
|
// Anchors
|
||||||
|
@ -256,7 +252,7 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateAndSubmitPassphrase() {
|
function validateAndSubmitPassphrase() {
|
||||||
if (passphraseField.text.length < 4) {
|
if (passphraseField.text.length < 3) {
|
||||||
setErrorText("Passphrase too short.");
|
setErrorText("Passphrase too short.");
|
||||||
return false;
|
return false;
|
||||||
} else if (passphraseField.text !== passphraseFieldAgain.text) {
|
} else if (passphraseField.text !== passphraseFieldAgain.text) {
|
||||||
|
|
|
@ -26,8 +26,6 @@ Rectangle {
|
||||||
id: root;
|
id: root;
|
||||||
|
|
||||||
property string activeView: "initialize";
|
property string activeView: "initialize";
|
||||||
property bool securityImageResultReceived: false;
|
|
||||||
property bool keyFilePathIfExistsResultReceived: false;
|
|
||||||
property bool keyboardRaised: false;
|
property bool keyboardRaised: false;
|
||||||
|
|
||||||
// Style
|
// Style
|
||||||
|
@ -40,25 +38,30 @@ Rectangle {
|
||||||
root.activeView = "needsLogIn";
|
root.activeView = "needsLogIn";
|
||||||
} else if (isLoggedIn) {
|
} else if (isLoggedIn) {
|
||||||
root.activeView = "initialize";
|
root.activeView = "initialize";
|
||||||
commerce.getSecurityImage();
|
|
||||||
commerce.getKeyFilePathIfExists();
|
commerce.getKeyFilePathIfExists();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onSecurityImageResult: {
|
onKeyFilePathIfExistsResult: {
|
||||||
securityImageResultReceived = true;
|
if (path === "" && root.activeView !== "notSetUp") {
|
||||||
if (!exists && root.activeView !== "notSetUp") { // "If security image is not set up"
|
|
||||||
root.activeView = "notSetUp";
|
root.activeView = "notSetUp";
|
||||||
} else if (root.securityImageResultReceived && exists && root.keyFilePathIfExistsResultReceived && root.activeView === "initialize") {
|
} else if (path !== "" && root.activeView === "initialize") {
|
||||||
root.activeView = "walletHome";
|
commerce.getSecurityImage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onKeyFilePathIfExistsResult: {
|
onSecurityImageResult: {
|
||||||
keyFilePathIfExistsResultReceived = true;
|
if (!exists && root.activeView !== "notSetUp") { // "If security image is not set up"
|
||||||
if (path === "" && root.activeView !== "notSetUp") {
|
|
||||||
root.activeView = "notSetUp";
|
root.activeView = "notSetUp";
|
||||||
} else if (root.securityImageResultReceived && root.keyFilePathIfExistsResultReceived && path !== "" && root.activeView === "initialize") {
|
} else if (exists && root.activeView === "initialize") {
|
||||||
|
commerce.getWalletAuthenticatedStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onWalletAuthenticatedStatusResult: {
|
||||||
|
if (!isAuthenticated && passphraseModal && !passphraseModal.visible) {
|
||||||
|
passphraseModal.visible = true;
|
||||||
|
} else if (isAuthenticated) {
|
||||||
root.activeView = "walletHome";
|
root.activeView = "walletHome";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,7 +92,8 @@ Rectangle {
|
||||||
if (msg.method === 'walletSetup_cancelClicked') {
|
if (msg.method === 'walletSetup_cancelClicked') {
|
||||||
walletSetupLightbox.visible = false;
|
walletSetupLightbox.visible = false;
|
||||||
} else if (msg.method === 'walletSetup_finished') {
|
} else if (msg.method === 'walletSetup_finished') {
|
||||||
root.activeView = "walletHome";
|
root.activeView = "initialize";
|
||||||
|
commerce.getLoginStatus();
|
||||||
} else if (msg.method === 'walletSetup_raiseKeyboard') {
|
} else if (msg.method === 'walletSetup_raiseKeyboard') {
|
||||||
root.keyboardRaised = true;
|
root.keyboardRaised = true;
|
||||||
} else if (msg.method === 'walletSetup_lowerKeyboard') {
|
} else if (msg.method === 'walletSetup_lowerKeyboard') {
|
||||||
|
@ -218,6 +222,21 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PassphraseModal {
|
||||||
|
id: passphraseModal;
|
||||||
|
visible: false;
|
||||||
|
anchors.top: titleBarContainer.bottom;
|
||||||
|
anchors.bottom: parent.bottom;
|
||||||
|
anchors.left: parent.left;
|
||||||
|
anchors.right: parent.right;
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
onSendSignalToParent: {
|
||||||
|
sendToScript(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
NotSetUp {
|
NotSetUp {
|
||||||
id: notSetUp;
|
id: notSetUp;
|
||||||
visible: root.activeView === "notSetUp";
|
visible: root.activeView === "notSetUp";
|
||||||
|
|
|
@ -38,7 +38,7 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
onBalanceResult : {
|
onBalanceResult : {
|
||||||
balanceText.text = parseFloat(result.data.balance/100).toFixed(2);
|
balanceText.text = result.data.balance;
|
||||||
}
|
}
|
||||||
|
|
||||||
onHistoryResult : {
|
onHistoryResult : {
|
||||||
|
@ -88,13 +88,14 @@ Item {
|
||||||
height: 60;
|
height: 60;
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: hfcBalanceField;
|
id: hfcBalanceField;
|
||||||
|
color: hifi.colors.darkGray;
|
||||||
anchors.right: parent.right;
|
anchors.right: parent.right;
|
||||||
anchors.left: parent.left;
|
anchors.left: parent.left;
|
||||||
anchors.bottom: parent.bottom;
|
anchors.bottom: parent.bottom;
|
||||||
height: parent.height - 15;
|
height: parent.height - 15;
|
||||||
|
|
||||||
// "HFC" balance label
|
// "HFC" balance label
|
||||||
RalewayRegular {
|
FiraSansRegular {
|
||||||
id: balanceLabel;
|
id: balanceLabel;
|
||||||
text: "HFC";
|
text: "HFC";
|
||||||
// Text size
|
// Text size
|
||||||
|
@ -106,7 +107,7 @@ Item {
|
||||||
anchors.rightMargin: 4;
|
anchors.rightMargin: 4;
|
||||||
width: paintedWidth;
|
width: paintedWidth;
|
||||||
// Style
|
// Style
|
||||||
color: hifi.colors.darkGray;
|
color: hifi.colors.lightGrayText;
|
||||||
// Alignment
|
// Alignment
|
||||||
horizontalAlignment: Text.AlignRight;
|
horizontalAlignment: Text.AlignRight;
|
||||||
verticalAlignment: Text.AlignVCenter;
|
verticalAlignment: Text.AlignVCenter;
|
||||||
|
@ -121,7 +122,7 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Balance Text
|
// Balance Text
|
||||||
FiraSansRegular {
|
FiraSansSemiBold {
|
||||||
id: balanceText;
|
id: balanceText;
|
||||||
text: "--";
|
text: "--";
|
||||||
// Text size
|
// Text size
|
||||||
|
@ -133,7 +134,7 @@ Item {
|
||||||
anchors.right: balanceLabel.left;
|
anchors.right: balanceLabel.left;
|
||||||
anchors.rightMargin: 4;
|
anchors.rightMargin: 4;
|
||||||
// Style
|
// Style
|
||||||
color: hifi.colors.darkGray;
|
color: hifi.colors.lightGrayText;
|
||||||
// Alignment
|
// Alignment
|
||||||
horizontalAlignment: Text.AlignRight;
|
horizontalAlignment: Text.AlignRight;
|
||||||
verticalAlignment: Text.AlignVCenter;
|
verticalAlignment: Text.AlignVCenter;
|
||||||
|
@ -258,7 +259,7 @@ Item {
|
||||||
delegate: Item {
|
delegate: Item {
|
||||||
width: parent.width;
|
width: parent.width;
|
||||||
height: transactionText.height + 30;
|
height: transactionText.height + 30;
|
||||||
RalewayRegular {
|
FiraSansRegular {
|
||||||
id: transactionText;
|
id: transactionText;
|
||||||
text: model.text;
|
text: model.text;
|
||||||
// Style
|
// Style
|
||||||
|
@ -272,7 +273,7 @@ Item {
|
||||||
horizontalAlignment: Text.AlignLeft;
|
horizontalAlignment: Text.AlignLeft;
|
||||||
verticalAlignment: Text.AlignVCenter;
|
verticalAlignment: Text.AlignVCenter;
|
||||||
}
|
}
|
||||||
|
|
||||||
HifiControlsUit.Separator {
|
HifiControlsUit.Separator {
|
||||||
anchors.left: parent.left;
|
anchors.left: parent.left;
|
||||||
anchors.right: parent.right;
|
anchors.right: parent.right;
|
||||||
|
@ -288,7 +289,7 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
// This should never be visible (since you immediately get 100 HFC)
|
// This should never be visible (since you immediately get 100 HFC)
|
||||||
RalewayRegular {
|
FiraSansRegular {
|
||||||
id: emptyTransationHistory;
|
id: emptyTransationHistory;
|
||||||
size: 24;
|
size: 24;
|
||||||
visible: !transactionHistory.visible && root.historyReceived;
|
visible: !transactionHistory.visible && root.historyReceived;
|
||||||
|
|
|
@ -39,9 +39,9 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onPassphraseSetupStatusResult: {
|
onWalletAuthenticatedStatusResult: {
|
||||||
securityImageContainer.visible = false;
|
securityImageContainer.visible = false;
|
||||||
if (passphraseIsSetup) {
|
if (isAuthenticated) {
|
||||||
privateKeysReadyContainer.visible = true;
|
privateKeysReadyContainer.visible = true;
|
||||||
} else {
|
} else {
|
||||||
choosePassphraseContainer.visible = true;
|
choosePassphraseContainer.visible = true;
|
||||||
|
@ -117,7 +117,7 @@ Rectangle {
|
||||||
anchors.right: parent.right;
|
anchors.right: parent.right;
|
||||||
anchors.rightMargin: 16;
|
anchors.rightMargin: 16;
|
||||||
height: 280;
|
height: 280;
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
onSendSignalToWallet: {
|
onSendSignalToWallet: {
|
||||||
sendSignalToWallet(msg);
|
sendSignalToWallet(msg);
|
||||||
|
@ -210,7 +210,7 @@ Rectangle {
|
||||||
|
|
||||||
onVisibleChanged: {
|
onVisibleChanged: {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
commerce.getPassphraseSetupStatus();
|
commerce.getWalletAuthenticatedStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import QtQuick 2.5
|
import QtQuick 2.5
|
||||||
import QtGraphicalEffects 1.0
|
import QtGraphicalEffects 1.0
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
|
||||||
import "../../styles-uit"
|
import "../../styles-uit"
|
||||||
import "../audio" as HifiAudio
|
import "../audio" as HifiAudio
|
||||||
|
@ -109,15 +110,45 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RalewaySemiBold {
|
Item {
|
||||||
id: usernameText
|
width: 150
|
||||||
text: tabletRoot.username
|
height: 50
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.rightMargin: 20
|
anchors.rightMargin: 30
|
||||||
horizontalAlignment: Text.AlignRight
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
font.pixelSize: 20
|
|
||||||
color: "#afafaf"
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ Item {
|
||||||
id: tabletRoot
|
id: tabletRoot
|
||||||
objectName: "tabletRoot"
|
objectName: "tabletRoot"
|
||||||
property string username: "Unknown user"
|
property string username: "Unknown user"
|
||||||
|
property string usernameShort: "Unknown user"
|
||||||
property var rootMenu;
|
property var rootMenu;
|
||||||
property var openModal: null;
|
property var openModal: null;
|
||||||
property var openMessage: null;
|
property var openMessage: null;
|
||||||
|
@ -157,6 +158,11 @@ Item {
|
||||||
|
|
||||||
function setUsername(newUsername) {
|
function setUsername(newUsername) {
|
||||||
username = newUsername;
|
username = newUsername;
|
||||||
|
usernameShort = newUsername.substring(0, 8);
|
||||||
|
|
||||||
|
if (newUsername.length > 8) {
|
||||||
|
usernameShort = usernameShort + "..."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListModel {
|
ListModel {
|
||||||
|
|
|
@ -604,6 +604,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
||||||
DependencyManager::registerInheritance<SpatialParentFinder, InterfaceParentFinder>();
|
DependencyManager::registerInheritance<SpatialParentFinder, InterfaceParentFinder>();
|
||||||
|
|
||||||
// Set dependencies
|
// Set dependencies
|
||||||
|
DependencyManager::set<Cursor::Manager>();
|
||||||
DependencyManager::set<AccountManager>(std::bind(&Application::getUserAgent, qApp));
|
DependencyManager::set<AccountManager>(std::bind(&Application::getUserAgent, qApp));
|
||||||
DependencyManager::set<StatTracker>();
|
DependencyManager::set<StatTracker>();
|
||||||
DependencyManager::set<ScriptEngines>(ScriptEngine::CLIENT_SCRIPT);
|
DependencyManager::set<ScriptEngines>(ScriptEngine::CLIENT_SCRIPT);
|
||||||
|
@ -6320,11 +6321,11 @@ bool Application::askToWearAvatarAttachmentUrl(const QString& url) {
|
||||||
|
|
||||||
bool Application::askToReplaceDomainContent(const QString& url) {
|
bool Application::askToReplaceDomainContent(const QString& url) {
|
||||||
QString methodDetails;
|
QString methodDetails;
|
||||||
|
const int MAX_CHARACTERS_PER_LINE = 90;
|
||||||
if (DependencyManager::get<NodeList>()->getThisNodeCanReplaceContent()) {
|
if (DependencyManager::get<NodeList>()->getThisNodeCanReplaceContent()) {
|
||||||
QUrl originURL { url };
|
QUrl originURL { url };
|
||||||
if (originURL.host().endsWith(MARKETPLACE_CDN_HOSTNAME)) {
|
if (originURL.host().endsWith(MARKETPLACE_CDN_HOSTNAME)) {
|
||||||
// Create a confirmation dialog when this call is made
|
// 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. "
|
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 "
|
"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) +
|
"and restoring content, visit the documentation page at: ", MAX_CHARACTERS_PER_LINE) +
|
||||||
|
@ -6360,7 +6361,9 @@ bool Application::askToReplaceDomainContent(const QString& url) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
methodDetails = "UserDoesNotHavePermissionToReplaceContent";
|
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);
|
QMessageBox::Ok, QMessageBox::Ok);
|
||||||
}
|
}
|
||||||
QJsonObject messageProperties = {
|
QJsonObject messageProperties = {
|
||||||
|
|
|
@ -1912,6 +1912,17 @@ void MyAvatar::preDisplaySide(RenderArgs* renderArgs) {
|
||||||
const bool shouldDrawHead = shouldRenderHead(renderArgs);
|
const bool shouldDrawHead = shouldRenderHead(renderArgs);
|
||||||
if (shouldDrawHead != _prevShouldDrawHead) {
|
if (shouldDrawHead != _prevShouldDrawHead) {
|
||||||
_skeletonModel->setEnableCauterization(!shouldDrawHead);
|
_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;
|
_prevShouldDrawHead = shouldDrawHead;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
|
#include <QTimeZone>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include "AccountManager.h"
|
#include "AccountManager.h"
|
||||||
#include "Wallet.h"
|
#include "Wallet.h"
|
||||||
|
@ -45,7 +46,6 @@ Handler(buy)
|
||||||
Handler(receiveAt)
|
Handler(receiveAt)
|
||||||
Handler(balance)
|
Handler(balance)
|
||||||
Handler(inventory)
|
Handler(inventory)
|
||||||
Handler(history)
|
|
||||||
|
|
||||||
void Ledger::send(const QString& endpoint, const QString& success, const QString& fail, QNetworkAccessManager::Operation method, QJsonObject request) {
|
void Ledger::send(const QString& endpoint, const QString& success, const QString& fail, QNetworkAccessManager::Operation method, QJsonObject request) {
|
||||||
auto accountManager = DependencyManager::get<AccountManager>();
|
auto accountManager = DependencyManager::get<AccountManager>();
|
||||||
|
@ -108,6 +108,64 @@ void Ledger::inventory(const QStringList& keys) {
|
||||||
keysQuery("inventory", "inventorySuccess", "inventoryFailure");
|
keysQuery("inventory", "inventorySuccess", "inventoryFailure");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString nameFromKey(const QString& key, const QStringList& publicKeys) {
|
||||||
|
if (key.isNull() || key.isEmpty()) {
|
||||||
|
return "<b>Marketplace</b>";
|
||||||
|
}
|
||||||
|
if (publicKeys.contains(key)) {
|
||||||
|
return "You";
|
||||||
|
}
|
||||||
|
return "<b>Someone</b>";
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ledger::historySuccess(QNetworkReply& reply) {
|
||||||
|
// here we send a historyResult with some extra stuff in it
|
||||||
|
// Namely, the styled text we'd like to show. The issue is the
|
||||||
|
// QML cannot do that easily since it doesn't know what the wallet
|
||||||
|
// public key(s) are. Let's keep it that way
|
||||||
|
QByteArray response = reply.readAll();
|
||||||
|
QJsonObject data = QJsonDocument::fromJson(response).object();
|
||||||
|
|
||||||
|
// we will need the array of public keys from the wallet
|
||||||
|
auto wallet = DependencyManager::get<Wallet>();
|
||||||
|
auto keys = wallet->listPublicKeys();
|
||||||
|
|
||||||
|
// now we need to loop through the transactions and add fancy text...
|
||||||
|
auto historyArray = data.find("data").value().toObject().find("history").value().toArray();
|
||||||
|
QJsonArray newHistoryArray;
|
||||||
|
|
||||||
|
// TODO: do this with 0 copies if possible
|
||||||
|
for(auto it = historyArray.begin(); it != historyArray.end(); it++) {
|
||||||
|
auto valueObject = (*it).toObject();
|
||||||
|
QString from = nameFromKey(valueObject["sender_key"].toString(), keys);
|
||||||
|
QString to = nameFromKey(valueObject["recipient_key"].toString(), keys);
|
||||||
|
// turns out on my machine, toLocalTime convert to some weird timezone, yet the
|
||||||
|
// systemTimeZone is correct. To avoid a strange bug with other's systems too, lets
|
||||||
|
// be explicit
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
|
QDateTime createdAt = QDateTime::fromTime_t(valueObject["created_at"].toInt(), Qt::UTC);
|
||||||
|
#else
|
||||||
|
QDateTime createdAt = QDateTime::fromSecsSinceEpoch(valueObject["created_at"].toInt(), Qt::UTC);
|
||||||
|
#endif
|
||||||
|
QDateTime localCreatedAt = createdAt.toTimeZone(QTimeZone::systemTimeZone());
|
||||||
|
valueObject["text"] = QString("%1 sent %2 <b>%3 %4</b> on %5 with message \"%6\"").
|
||||||
|
arg(from, to, QString::number(valueObject["quantity"].toInt()), valueObject["asset_title"].toString(), localCreatedAt.toString(Qt::SystemLocaleShortDate), valueObject["message"].toString());
|
||||||
|
newHistoryArray.push_back(valueObject);
|
||||||
|
}
|
||||||
|
// now copy the rest of the json -- this is inefficient
|
||||||
|
// TODO: try to do this without making copies
|
||||||
|
QJsonObject newData;
|
||||||
|
newData["status"] = "success";
|
||||||
|
QJsonObject newDataData;
|
||||||
|
newDataData["history"] = newHistoryArray;
|
||||||
|
newData["data"] = newDataData;
|
||||||
|
emit historyResult(newData);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ledger::historyFailure(QNetworkReply& reply) {
|
||||||
|
failResponse("history", reply);
|
||||||
|
}
|
||||||
|
|
||||||
void Ledger::history(const QStringList& keys) {
|
void Ledger::history(const QStringList& keys) {
|
||||||
keysQuery("history", "historySuccess", "historyFailure");
|
keysQuery("history", "historySuccess", "historyFailure");
|
||||||
}
|
}
|
||||||
|
@ -117,4 +175,4 @@ void Ledger::resetSuccess(QNetworkReply& reply) { apiResponse("reset", reply); }
|
||||||
void Ledger::resetFailure(QNetworkReply& reply) { failResponse("reset", reply); }
|
void Ledger::resetFailure(QNetworkReply& reply) { failResponse("reset", reply); }
|
||||||
void Ledger::reset() {
|
void Ledger::reset() {
|
||||||
send("reset_user_hfc_account", "resetSuccess", "resetFailure", QNetworkAccessManager::PutOperation, QJsonObject());
|
send("reset_user_hfc_account", "resetSuccess", "resetFailure", QNetworkAccessManager::PutOperation, QJsonObject());
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,30 @@ QmlCommerce::QmlCommerce(QQuickItem* parent) : OffscreenQmlDialog(parent) {
|
||||||
connect(wallet.data(), &Wallet::keyFilePathIfExistsResult, this, &QmlCommerce::keyFilePathIfExistsResult);
|
connect(wallet.data(), &Wallet::keyFilePathIfExistsResult, this, &QmlCommerce::keyFilePathIfExistsResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QmlCommerce::getLoginStatus() {
|
||||||
|
emit loginStatusResult(DependencyManager::get<AccountManager>()->isLoggedIn());
|
||||||
|
}
|
||||||
|
|
||||||
|
void QmlCommerce::getKeyFilePathIfExists() {
|
||||||
|
auto wallet = DependencyManager::get<Wallet>();
|
||||||
|
wallet->sendKeyFilePathIfExists();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QmlCommerce::getWalletAuthenticatedStatus() {
|
||||||
|
auto wallet = DependencyManager::get<Wallet>();
|
||||||
|
emit walletAuthenticatedStatusResult(wallet->walletIsAuthenticatedWithPassphrase());
|
||||||
|
}
|
||||||
|
|
||||||
|
void QmlCommerce::getSecurityImage() {
|
||||||
|
auto wallet = DependencyManager::get<Wallet>();
|
||||||
|
wallet->getSecurityImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QmlCommerce::chooseSecurityImage(const QString& imageFile) {
|
||||||
|
auto wallet = DependencyManager::get<Wallet>();
|
||||||
|
wallet->chooseSecurityImage(imageFile);
|
||||||
|
}
|
||||||
|
|
||||||
void QmlCommerce::buy(const QString& assetId, int cost, const QString& buyerUsername) {
|
void QmlCommerce::buy(const QString& assetId, int cost, const QString& buyerUsername) {
|
||||||
auto ledger = DependencyManager::get<Ledger>();
|
auto ledger = DependencyManager::get<Ledger>();
|
||||||
auto wallet = DependencyManager::get<Wallet>();
|
auto wallet = DependencyManager::get<Wallet>();
|
||||||
|
@ -60,30 +84,14 @@ void QmlCommerce::history() {
|
||||||
ledger->history(wallet->listPublicKeys());
|
ledger->history(wallet->listPublicKeys());
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlCommerce::chooseSecurityImage(const QString& imageFile) {
|
|
||||||
auto wallet = DependencyManager::get<Wallet>();
|
|
||||||
wallet->chooseSecurityImage(imageFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
void QmlCommerce::getSecurityImage() {
|
|
||||||
auto wallet = DependencyManager::get<Wallet>();
|
|
||||||
wallet->getSecurityImage();
|
|
||||||
}
|
|
||||||
|
|
||||||
void QmlCommerce::getLoginStatus() {
|
|
||||||
emit loginStatusResult(DependencyManager::get<AccountManager>()->isLoggedIn());
|
|
||||||
}
|
|
||||||
|
|
||||||
void QmlCommerce::setPassphrase(const QString& passphrase) {
|
void QmlCommerce::setPassphrase(const QString& passphrase) {
|
||||||
emit passphraseSetupStatusResult(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void QmlCommerce::getPassphraseSetupStatus() {
|
|
||||||
emit passphraseSetupStatusResult(false);
|
|
||||||
}
|
|
||||||
void QmlCommerce::getKeyFilePathIfExists() {
|
|
||||||
auto wallet = DependencyManager::get<Wallet>();
|
auto wallet = DependencyManager::get<Wallet>();
|
||||||
wallet->sendKeyFilePathIfExists();
|
if (wallet->getPassphrase() && !wallet->getPassphrase()->isEmpty()) {
|
||||||
|
wallet->changePassphrase(passphrase);
|
||||||
|
} else {
|
||||||
|
wallet->setPassphrase(passphrase);
|
||||||
|
}
|
||||||
|
getWalletAuthenticatedStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlCommerce::reset() {
|
void QmlCommerce::reset() {
|
||||||
|
@ -91,4 +99,4 @@ void QmlCommerce::reset() {
|
||||||
auto wallet = DependencyManager::get<Wallet>();
|
auto wallet = DependencyManager::get<Wallet>();
|
||||||
ledger->reset();
|
ledger->reset();
|
||||||
wallet->reset();
|
wallet->reset();
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,28 +28,32 @@ public:
|
||||||
QmlCommerce(QQuickItem* parent = nullptr);
|
QmlCommerce(QQuickItem* parent = nullptr);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
void loginStatusResult(bool isLoggedIn);
|
||||||
|
void keyFilePathIfExistsResult(const QString& path);
|
||||||
|
void securityImageResult(bool exists);
|
||||||
|
void walletAuthenticatedStatusResult(bool isAuthenticated);
|
||||||
|
|
||||||
void buyResult(QJsonObject result);
|
void buyResult(QJsonObject result);
|
||||||
// Balance and Inventory are NOT properties, because QML can't change them (without risk of failure), and
|
// Balance and Inventory are NOT properties, because QML can't change them (without risk of failure), and
|
||||||
// because we can't scalably know of out-of-band changes (e.g., another machine interacting with the block chain).
|
// because we can't scalably know of out-of-band changes (e.g., another machine interacting with the block chain).
|
||||||
void balanceResult(QJsonObject result);
|
void balanceResult(QJsonObject result);
|
||||||
void inventoryResult(QJsonObject result);
|
void inventoryResult(QJsonObject result);
|
||||||
void securityImageResult(bool exists);
|
|
||||||
void loginStatusResult(bool isLoggedIn);
|
|
||||||
void passphraseSetupStatusResult(bool passphraseIsSetup);
|
|
||||||
void historyResult(QJsonObject result);
|
void historyResult(QJsonObject result);
|
||||||
void keyFilePathIfExistsResult(const QString& path);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
Q_INVOKABLE void getLoginStatus();
|
||||||
|
Q_INVOKABLE void getKeyFilePathIfExists();
|
||||||
|
Q_INVOKABLE void getSecurityImage();
|
||||||
|
Q_INVOKABLE void getWalletAuthenticatedStatus();
|
||||||
|
|
||||||
|
Q_INVOKABLE void chooseSecurityImage(const QString& imageFile);
|
||||||
|
Q_INVOKABLE void setPassphrase(const QString& passphrase);
|
||||||
|
|
||||||
Q_INVOKABLE void buy(const QString& assetId, int cost, const QString& buyerUsername = "");
|
Q_INVOKABLE void buy(const QString& assetId, int cost, const QString& buyerUsername = "");
|
||||||
Q_INVOKABLE void balance();
|
Q_INVOKABLE void balance();
|
||||||
Q_INVOKABLE void inventory();
|
Q_INVOKABLE void inventory();
|
||||||
Q_INVOKABLE void history();
|
Q_INVOKABLE void history();
|
||||||
Q_INVOKABLE void chooseSecurityImage(const QString& imageFile);
|
|
||||||
Q_INVOKABLE void getSecurityImage();
|
|
||||||
Q_INVOKABLE void getLoginStatus();
|
|
||||||
Q_INVOKABLE void setPassphrase(const QString& passphrase);
|
|
||||||
Q_INVOKABLE void getPassphraseSetupStatus();
|
|
||||||
Q_INVOKABLE void getKeyFilePathIfExists();
|
|
||||||
Q_INVOKABLE void reset();
|
Q_INVOKABLE void reset();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -56,16 +56,72 @@ QString imageFilePath() {
|
||||||
int passwordCallback(char* password, int maxPasswordSize, int rwFlag, void* u) {
|
int passwordCallback(char* password, int maxPasswordSize, int rwFlag, void* u) {
|
||||||
// just return a hardcoded pwd for now
|
// just return a hardcoded pwd for now
|
||||||
auto passphrase = DependencyManager::get<Wallet>()->getPassphrase();
|
auto passphrase = DependencyManager::get<Wallet>()->getPassphrase();
|
||||||
if (passphrase) {
|
if (passphrase && !passphrase->isEmpty()) {
|
||||||
strcpy(password, passphrase->toLocal8Bit().constData());
|
strcpy(password, passphrase->toLocal8Bit().constData());
|
||||||
return static_cast<int>(passphrase->size());
|
return static_cast<int>(passphrase->size());
|
||||||
} else {
|
} else {
|
||||||
// ok gotta bring up modal dialog... But right now lets just
|
// this shouldn't happen - so lets log it to tell us we have
|
||||||
// just keep it empty
|
// a problem with the flow...
|
||||||
|
qCCritical(commerce) << "no cached passphrase while decrypting!";
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RSA* readKeys(const char* filename) {
|
||||||
|
FILE* fp;
|
||||||
|
RSA* key = NULL;
|
||||||
|
if ((fp = fopen(filename, "rt"))) {
|
||||||
|
// file opened successfully
|
||||||
|
qCDebug(commerce) << "opened key file" << filename;
|
||||||
|
if ((key = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL))) {
|
||||||
|
// now read private key
|
||||||
|
|
||||||
|
qCDebug(commerce) << "read public key";
|
||||||
|
|
||||||
|
if ((key = PEM_read_RSAPrivateKey(fp, &key, passwordCallback, NULL))) {
|
||||||
|
qCDebug(commerce) << "read private key";
|
||||||
|
fclose(fp);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
qCDebug(commerce) << "failed to read private key";
|
||||||
|
} else {
|
||||||
|
qCDebug(commerce) << "failed to read public key";
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
} else {
|
||||||
|
qCDebug(commerce) << "failed to open key file" << filename;
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool writeKeys(const char* filename, RSA* keys) {
|
||||||
|
FILE* fp;
|
||||||
|
bool retval = false;
|
||||||
|
if ((fp = fopen(filename, "wt"))) {
|
||||||
|
if (!PEM_write_RSAPublicKey(fp, keys)) {
|
||||||
|
fclose(fp);
|
||||||
|
qCDebug(commerce) << "failed to write public key";
|
||||||
|
QFile(QString(filename)).remove();
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!PEM_write_RSAPrivateKey(fp, keys, EVP_des_ede3_cbc(), NULL, 0, passwordCallback, NULL)) {
|
||||||
|
fclose(fp);
|
||||||
|
qCDebug(commerce) << "failed to write private key";
|
||||||
|
QFile(QString(filename)).remove();
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = true;
|
||||||
|
qCDebug(commerce) << "wrote keys successfully";
|
||||||
|
fclose(fp);
|
||||||
|
} else {
|
||||||
|
qCDebug(commerce) << "failed to open key file" << filename;
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// BEGIN copied code - this will be removed/changed at some point soon
|
// BEGIN copied code - this will be removed/changed at some point soon
|
||||||
// copied (without emits for various signals) from libraries/networking/src/RSAKeypairGenerator.cpp.
|
// copied (without emits for various signals) from libraries/networking/src/RSAKeypairGenerator.cpp.
|
||||||
// We will have a different implementation in practice, but this gives us a start for now
|
// We will have a different implementation in practice, but this gives us a start for now
|
||||||
|
@ -124,25 +180,9 @@ QPair<QByteArray*, QByteArray*> generateRSAKeypair() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!writeKeys(keyFilePath().toStdString().c_str(), keyPair)) {
|
||||||
// now lets persist them to files
|
qCDebug(commerce) << "couldn't save keys!";
|
||||||
// FIXME: for now I'm appending to the file if it exists. As long as we always put
|
return retval;
|
||||||
// the keys in the same order, this works fine. TODO: verify this will skip over
|
|
||||||
// anything else (like an embedded image)
|
|
||||||
FILE* fp;
|
|
||||||
if ((fp = fopen(keyFilePath().toStdString().c_str(), "at"))) {
|
|
||||||
if (!PEM_write_RSAPublicKey(fp, keyPair)) {
|
|
||||||
fclose(fp);
|
|
||||||
qCDebug(commerce) << "failed to write public key";
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!PEM_write_RSAPrivateKey(fp, keyPair, EVP_des_ede3_cbc(), NULL, 0, passwordCallback, NULL)) {
|
|
||||||
fclose(fp);
|
|
||||||
qCDebug(commerce) << "failed to write private key";
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
fclose(fp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RSA_free(keyPair);
|
RSA_free(keyPair);
|
||||||
|
@ -201,9 +241,6 @@ RSA* readPrivateKey(const char* filename) {
|
||||||
// file opened successfully
|
// file opened successfully
|
||||||
qCDebug(commerce) << "opened key file" << filename;
|
qCDebug(commerce) << "opened key file" << filename;
|
||||||
if ((key = PEM_read_RSAPrivateKey(fp, &key, passwordCallback, NULL))) {
|
if ((key = PEM_read_RSAPrivateKey(fp, &key, passwordCallback, NULL))) {
|
||||||
// cleanup
|
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
qCDebug(commerce) << "parsed private key file successfully";
|
qCDebug(commerce) << "parsed private key file successfully";
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -215,7 +252,6 @@ RSA* readPrivateKey(const char* filename) {
|
||||||
}
|
}
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const unsigned char IVEC[16] = "IAmAnIVecYay123";
|
static const unsigned char IVEC[16] = "IAmAnIVecYay123";
|
||||||
|
|
||||||
void initializeAESKeys(unsigned char* ivec, unsigned char* ckey, const QByteArray& salt) {
|
void initializeAESKeys(unsigned char* ivec, unsigned char* ckey, const QByteArray& salt) {
|
||||||
|
@ -236,6 +272,10 @@ void Wallet::setPassphrase(const QString& passphrase) {
|
||||||
delete _passphrase;
|
delete _passphrase;
|
||||||
}
|
}
|
||||||
_passphrase = new QString(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
|
// encrypt some stuff
|
||||||
|
@ -341,6 +381,38 @@ bool Wallet::decryptFile(const QString& inputFilePath, unsigned char** outputBuf
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Wallet::walletIsAuthenticatedWithPassphrase() {
|
||||||
|
// try to read existing keys if they exist...
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool Wallet::createIfNeeded() {
|
bool Wallet::createIfNeeded() {
|
||||||
if (_publicKeys.count() > 0) return false;
|
if (_publicKeys.count() > 0) return false;
|
||||||
|
|
||||||
|
@ -512,3 +584,30 @@ void Wallet::reset() {
|
||||||
keyFile.remove();
|
keyFile.remove();
|
||||||
imageFile.remove();
|
imageFile.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Wallet::changePassphrase(const QString& newPassphrase) {
|
||||||
|
qCDebug(commerce) << "changing passphrase";
|
||||||
|
RSA* keys = readKeys(keyFilePath().toStdString().c_str());
|
||||||
|
if (keys) {
|
||||||
|
// we read successfully, so now write to a new temp file
|
||||||
|
// save old passphrase just in case
|
||||||
|
// TODO: force re-enter?
|
||||||
|
QString oldPassphrase = *_passphrase;
|
||||||
|
setPassphrase(newPassphrase);
|
||||||
|
QString tempFileName = QString("%1.%2").arg(keyFilePath(), QString("temp"));
|
||||||
|
if (writeKeys(tempFileName.toStdString().c_str(), keys)) {
|
||||||
|
// ok, now move the temp file to the correct spot
|
||||||
|
QFile(QString(keyFilePath())).remove();
|
||||||
|
QFile(tempFileName).rename(QString(keyFilePath()));
|
||||||
|
qCDebug(commerce) << "passphrase changed successfully";
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
qCDebug(commerce) << "couldn't write keys";
|
||||||
|
QFile(tempFileName).remove();
|
||||||
|
setPassphrase(oldPassphrase);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qCDebug(commerce) << "couldn't read keys";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
@ -39,18 +39,21 @@ public:
|
||||||
|
|
||||||
void setPassphrase(const QString& passphrase);
|
void setPassphrase(const QString& passphrase);
|
||||||
QString* getPassphrase() { return _passphrase; }
|
QString* getPassphrase() { return _passphrase; }
|
||||||
|
bool getPassphraseIsCached() { return !(_passphrase->isEmpty()); }
|
||||||
|
bool walletIsAuthenticatedWithPassphrase();
|
||||||
|
bool changePassphrase(const QString& newPassphrase);
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void securityImageResult(bool exists) ;
|
void securityImageResult(bool exists);
|
||||||
void keyFilePathIfExistsResult(const QString& path);
|
void keyFilePathIfExistsResult(const QString& path);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QStringList _publicKeys{};
|
QStringList _publicKeys{};
|
||||||
QPixmap* _securityImage { nullptr };
|
QPixmap* _securityImage { nullptr };
|
||||||
QByteArray _salt {"iamsalt!"};
|
QByteArray _salt {"iamsalt!"};
|
||||||
QString* _passphrase { new QString("pwd") };
|
QString* _passphrase { new QString("") };
|
||||||
|
|
||||||
void updateImageProvider();
|
void updateImageProvider();
|
||||||
bool encryptFile(const QString& inputFilePath, const QString& outputFilePath);
|
bool encryptFile(const QString& inputFilePath, const QString& outputFilePath);
|
||||||
|
|
|
@ -18,6 +18,8 @@ AccountScriptingInterface* AccountScriptingInterface::getInstance() {
|
||||||
auto accountManager = DependencyManager::get<AccountManager>();
|
auto accountManager = DependencyManager::get<AccountManager>();
|
||||||
QObject::connect(accountManager.data(), &AccountManager::profileChanged,
|
QObject::connect(accountManager.data(), &AccountManager::profileChanged,
|
||||||
&sharedInstance, &AccountScriptingInterface::usernameChanged);
|
&sharedInstance, &AccountScriptingInterface::usernameChanged);
|
||||||
|
QObject::connect(accountManager.data(), &AccountManager::usernameChanged,
|
||||||
|
&sharedInstance, &AccountScriptingInterface::onUsernameChanged);
|
||||||
return &sharedInstance;
|
return &sharedInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +33,21 @@ bool AccountScriptingInterface::checkAndSignalForAccessToken() {
|
||||||
return accountManager->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() {
|
QString AccountScriptingInterface::getUsername() {
|
||||||
auto accountManager = DependencyManager::get<AccountManager>();
|
auto accountManager = DependencyManager::get<AccountManager>();
|
||||||
if (accountManager->isLoggedIn()) {
|
if (accountManager->isLoggedIn()) {
|
||||||
|
|
|
@ -18,6 +18,7 @@ class AccountScriptingInterface : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
Q_PROPERTY(QString username READ getUsername NOTIFY usernameChanged)
|
Q_PROPERTY(QString username READ getUsername NOTIFY usernameChanged)
|
||||||
|
Q_PROPERTY(bool loggedIn READ loggedIn NOTIFY loggedInChanged)
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* @namespace Account
|
* @namespace Account
|
||||||
|
@ -32,6 +33,7 @@ signals:
|
||||||
* @return {Signal}
|
* @return {Signal}
|
||||||
*/
|
*/
|
||||||
void usernameChanged();
|
void usernameChanged();
|
||||||
|
void loggedInChanged(bool loggedIn);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
static AccountScriptingInterface* getInstance();
|
static AccountScriptingInterface* getInstance();
|
||||||
|
@ -50,6 +52,20 @@ public slots:
|
||||||
*/
|
*/
|
||||||
bool isLoggedIn();
|
bool isLoggedIn();
|
||||||
bool checkAndSignalForAccessToken();
|
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
|
#endif // hifi_AccountScriptingInterface_h
|
||||||
|
|
|
@ -33,7 +33,12 @@ void DialogsManagerScriptingInterface::showAddressBar() {
|
||||||
|
|
||||||
void DialogsManagerScriptingInterface::hideAddressBar() {
|
void DialogsManagerScriptingInterface::hideAddressBar() {
|
||||||
QMetaObject::invokeMethod(DependencyManager::get<DialogsManager>().data(),
|
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() {
|
void DialogsManagerScriptingInterface::showFeed() {
|
||||||
|
|
|
@ -24,6 +24,7 @@ public:
|
||||||
public slots:
|
public slots:
|
||||||
void showAddressBar();
|
void showAddressBar();
|
||||||
void hideAddressBar();
|
void hideAddressBar();
|
||||||
|
void showLoginDialog();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void addressBarShown(bool visible);
|
void addressBarShown(bool visible);
|
||||||
|
|
|
@ -910,6 +910,8 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
|
||||||
|
|
||||||
const QVector<FBXAnimationFrame>& frames = _animation->getFramesReference(); // NOTE: getFrames() is too heavy
|
const QVector<FBXAnimationFrame>& frames = _animation->getFramesReference(); // NOTE: getFrames() is too heavy
|
||||||
auto& fbxJoints = _animation->getGeometry().joints;
|
auto& fbxJoints = _animation->getGeometry().joints;
|
||||||
|
auto& originalFbxJoints = _model->getFBXGeometry().joints;
|
||||||
|
bool allowTranslation = entity->getAnimationAllowTranslation();
|
||||||
int frameCount = frames.size();
|
int frameCount = frames.size();
|
||||||
if (frameCount <= 0) {
|
if (frameCount <= 0) {
|
||||||
return;
|
return;
|
||||||
|
@ -952,7 +954,9 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
|
||||||
int index = _jointMapping[j];
|
int index = _jointMapping[j];
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
glm::mat4 translationMat;
|
glm::mat4 translationMat;
|
||||||
if (index < translations.size()) {
|
if (!allowTranslation){
|
||||||
|
translationMat = glm::translate(originalFbxJoints[index].translation);
|
||||||
|
} else if (index < translations.size()) {
|
||||||
translationMat = glm::translate(translations[index]);
|
translationMat = glm::translate(translations[index]);
|
||||||
}
|
}
|
||||||
glm::mat4 rotationMat;
|
glm::mat4 rotationMat;
|
||||||
|
|
|
@ -33,6 +33,7 @@ bool operator==(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b
|
||||||
|
|
||||||
void AnimationPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const {
|
void AnimationPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const {
|
||||||
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_URL, Animation, animation, URL, url);
|
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_URL, Animation, animation, URL, url);
|
||||||
|
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_ALLOW_TRANSLATION, Animation, animation, AllowTranslation, allowTranslation);
|
||||||
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_FPS, Animation, animation, FPS, fps);
|
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_FPS, Animation, animation, FPS, fps);
|
||||||
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_FRAME_INDEX, Animation, animation, CurrentFrame, currentFrame);
|
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_FRAME_INDEX, Animation, animation, CurrentFrame, currentFrame);
|
||||||
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_PLAYING, Animation, animation, Running, running);
|
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_PLAYING, Animation, animation, Running, running);
|
||||||
|
@ -46,6 +47,7 @@ void AnimationPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desire
|
||||||
void AnimationPropertyGroup::copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) {
|
void AnimationPropertyGroup::copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) {
|
||||||
|
|
||||||
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, url, QString, setURL);
|
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, url, QString, setURL);
|
||||||
|
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, allowTranslation, bool, setAllowTranslation);
|
||||||
|
|
||||||
// legacy property support
|
// legacy property support
|
||||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(animationURL, QString, setURL, getURL);
|
COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(animationURL, QString, setURL, getURL);
|
||||||
|
@ -67,6 +69,7 @@ void AnimationPropertyGroup::copyFromScriptValue(const QScriptValue& object, boo
|
||||||
|
|
||||||
void AnimationPropertyGroup::merge(const AnimationPropertyGroup& other) {
|
void AnimationPropertyGroup::merge(const AnimationPropertyGroup& other) {
|
||||||
COPY_PROPERTY_IF_CHANGED(url);
|
COPY_PROPERTY_IF_CHANGED(url);
|
||||||
|
COPY_PROPERTY_IF_CHANGED(allowTranslation);
|
||||||
COPY_PROPERTY_IF_CHANGED(fps);
|
COPY_PROPERTY_IF_CHANGED(fps);
|
||||||
COPY_PROPERTY_IF_CHANGED(currentFrame);
|
COPY_PROPERTY_IF_CHANGED(currentFrame);
|
||||||
COPY_PROPERTY_IF_CHANGED(running);
|
COPY_PROPERTY_IF_CHANGED(running);
|
||||||
|
@ -88,6 +91,7 @@ void AnimationPropertyGroup::setFromOldAnimationSettings(const QString& value) {
|
||||||
float lastFrame = getLastFrame();
|
float lastFrame = getLastFrame();
|
||||||
bool loop = getLoop();
|
bool loop = getLoop();
|
||||||
bool hold = getHold();
|
bool hold = getHold();
|
||||||
|
bool allowTranslation = getAllowTranslation();
|
||||||
|
|
||||||
QJsonDocument settingsAsJson = QJsonDocument::fromJson(value.toUtf8());
|
QJsonDocument settingsAsJson = QJsonDocument::fromJson(value.toUtf8());
|
||||||
QJsonObject settingsAsJsonObject = settingsAsJson.object();
|
QJsonObject settingsAsJsonObject = settingsAsJson.object();
|
||||||
|
@ -122,6 +126,11 @@ void AnimationPropertyGroup::setFromOldAnimationSettings(const QString& value) {
|
||||||
running = settingsMap["hold"].toBool();
|
running = settingsMap["hold"].toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (settingsMap.contains("allowTranslation")) {
|
||||||
|
allowTranslation = settingsMap["allowTranslation"].toBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
setAllowTranslation(allowTranslation);
|
||||||
setFPS(fps);
|
setFPS(fps);
|
||||||
setCurrentFrame(currentFrame);
|
setCurrentFrame(currentFrame);
|
||||||
setRunning(running);
|
setRunning(running);
|
||||||
|
@ -137,6 +146,7 @@ void AnimationPropertyGroup::debugDump() const {
|
||||||
qCDebug(entities) << " url:" << getURL() << " has changed:" << urlChanged();
|
qCDebug(entities) << " url:" << getURL() << " has changed:" << urlChanged();
|
||||||
qCDebug(entities) << " fps:" << getFPS() << " has changed:" << fpsChanged();
|
qCDebug(entities) << " fps:" << getFPS() << " has changed:" << fpsChanged();
|
||||||
qCDebug(entities) << "currentFrame:" << getCurrentFrame() << " has changed:" << currentFrameChanged();
|
qCDebug(entities) << "currentFrame:" << getCurrentFrame() << " has changed:" << currentFrameChanged();
|
||||||
|
qCDebug(entities) << "allowTranslation:" << getAllowTranslation() << " has changed:" << allowTranslationChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimationPropertyGroup::listChangedProperties(QList<QString>& out) {
|
void AnimationPropertyGroup::listChangedProperties(QList<QString>& out) {
|
||||||
|
@ -149,6 +159,9 @@ void AnimationPropertyGroup::listChangedProperties(QList<QString>& out) {
|
||||||
if (currentFrameChanged()) {
|
if (currentFrameChanged()) {
|
||||||
out << "animation-currentFrame";
|
out << "animation-currentFrame";
|
||||||
}
|
}
|
||||||
|
if (allowTranslationChanged()) {
|
||||||
|
out << "animation-allowTranslation";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -162,6 +175,7 @@ bool AnimationPropertyGroup::appendToEditPacket(OctreePacketData* packetData,
|
||||||
bool successPropertyFits = true;
|
bool successPropertyFits = true;
|
||||||
|
|
||||||
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_URL, getURL());
|
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_URL, getURL());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_ALLOW_TRANSLATION, getAllowTranslation());
|
||||||
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, getFPS());
|
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, getFPS());
|
||||||
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, getCurrentFrame());
|
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, getCurrentFrame());
|
||||||
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, getRunning());
|
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, getRunning());
|
||||||
|
@ -181,6 +195,7 @@ bool AnimationPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyF
|
||||||
bool somethingChanged = false;
|
bool somethingChanged = false;
|
||||||
|
|
||||||
READ_ENTITY_PROPERTY(PROP_ANIMATION_URL, QString, setURL);
|
READ_ENTITY_PROPERTY(PROP_ANIMATION_URL, QString, setURL);
|
||||||
|
READ_ENTITY_PROPERTY(PROP_ANIMATION_ALLOW_TRANSLATION, bool, setAllowTranslation);
|
||||||
|
|
||||||
READ_ENTITY_PROPERTY(PROP_ANIMATION_FPS, float, setFPS);
|
READ_ENTITY_PROPERTY(PROP_ANIMATION_FPS, float, setFPS);
|
||||||
READ_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, float, setCurrentFrame);
|
READ_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, float, setCurrentFrame);
|
||||||
|
@ -198,7 +213,8 @@ bool AnimationPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyF
|
||||||
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_FIRST_FRAME, FirstFrame);
|
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_FIRST_FRAME, FirstFrame);
|
||||||
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_LAST_FRAME, LastFrame);
|
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_LAST_FRAME, LastFrame);
|
||||||
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_HOLD, Hold);
|
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_HOLD, Hold);
|
||||||
|
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_ALLOW_TRANSLATION, AllowTranslation);
|
||||||
|
|
||||||
processedBytes += bytesRead;
|
processedBytes += bytesRead;
|
||||||
|
|
||||||
Q_UNUSED(somethingChanged);
|
Q_UNUSED(somethingChanged);
|
||||||
|
@ -215,6 +231,7 @@ void AnimationPropertyGroup::markAllChanged() {
|
||||||
_firstFrameChanged = true;
|
_firstFrameChanged = true;
|
||||||
_lastFrameChanged = true;
|
_lastFrameChanged = true;
|
||||||
_holdChanged = true;
|
_holdChanged = true;
|
||||||
|
_allowTranslationChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityPropertyFlags AnimationPropertyGroup::getChangedProperties() const {
|
EntityPropertyFlags AnimationPropertyGroup::getChangedProperties() const {
|
||||||
|
@ -228,12 +245,14 @@ EntityPropertyFlags AnimationPropertyGroup::getChangedProperties() const {
|
||||||
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_FIRST_FRAME, firstFrame);
|
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_FIRST_FRAME, firstFrame);
|
||||||
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_LAST_FRAME, lastFrame);
|
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_LAST_FRAME, lastFrame);
|
||||||
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_HOLD, hold);
|
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_HOLD, hold);
|
||||||
|
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_ALLOW_TRANSLATION, allowTranslation);
|
||||||
|
|
||||||
return changedProperties;
|
return changedProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimationPropertyGroup::getProperties(EntityItemProperties& properties) const {
|
void AnimationPropertyGroup::getProperties(EntityItemProperties& properties) const {
|
||||||
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, URL, getURL);
|
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, URL, getURL);
|
||||||
|
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, AllowTranslation, getAllowTranslation);
|
||||||
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, FPS, getFPS);
|
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, FPS, getFPS);
|
||||||
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, CurrentFrame, getCurrentFrame);
|
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, CurrentFrame, getCurrentFrame);
|
||||||
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, Running, getRunning);
|
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, Running, getRunning);
|
||||||
|
@ -247,6 +266,7 @@ bool AnimationPropertyGroup::setProperties(const EntityItemProperties& propertie
|
||||||
bool somethingChanged = false;
|
bool somethingChanged = false;
|
||||||
|
|
||||||
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, URL, url, setURL);
|
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, URL, url, setURL);
|
||||||
|
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, AllowTranslation, allowTranslation, setAllowTranslation);
|
||||||
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, FPS, fps, setFPS);
|
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, FPS, fps, setFPS);
|
||||||
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, CurrentFrame, currentFrame, setCurrentFrame);
|
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, CurrentFrame, currentFrame, setCurrentFrame);
|
||||||
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, Running, running, setRunning);
|
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, Running, running, setRunning);
|
||||||
|
@ -268,6 +288,7 @@ EntityPropertyFlags AnimationPropertyGroup::getEntityProperties(EncodeBitstreamP
|
||||||
requestedProperties += PROP_ANIMATION_FIRST_FRAME;
|
requestedProperties += PROP_ANIMATION_FIRST_FRAME;
|
||||||
requestedProperties += PROP_ANIMATION_LAST_FRAME;
|
requestedProperties += PROP_ANIMATION_LAST_FRAME;
|
||||||
requestedProperties += PROP_ANIMATION_HOLD;
|
requestedProperties += PROP_ANIMATION_HOLD;
|
||||||
|
requestedProperties += PROP_ANIMATION_ALLOW_TRANSLATION;
|
||||||
|
|
||||||
return requestedProperties;
|
return requestedProperties;
|
||||||
}
|
}
|
||||||
|
@ -283,6 +304,7 @@ void AnimationPropertyGroup::appendSubclassData(OctreePacketData* packetData, En
|
||||||
bool successPropertyFits = true;
|
bool successPropertyFits = true;
|
||||||
|
|
||||||
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_URL, getURL());
|
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_URL, getURL());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_ALLOW_TRANSLATION, getAllowTranslation());
|
||||||
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, getFPS());
|
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, getFPS());
|
||||||
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, getCurrentFrame());
|
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, getCurrentFrame());
|
||||||
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, getRunning());
|
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, getRunning());
|
||||||
|
@ -301,6 +323,7 @@ int AnimationPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char
|
||||||
const unsigned char* dataAt = data;
|
const unsigned char* dataAt = data;
|
||||||
|
|
||||||
READ_ENTITY_PROPERTY(PROP_ANIMATION_URL, QString, setURL);
|
READ_ENTITY_PROPERTY(PROP_ANIMATION_URL, QString, setURL);
|
||||||
|
READ_ENTITY_PROPERTY(PROP_ANIMATION_ALLOW_TRANSLATION, bool, setAllowTranslation);
|
||||||
READ_ENTITY_PROPERTY(PROP_ANIMATION_FPS, float, setFPS);
|
READ_ENTITY_PROPERTY(PROP_ANIMATION_FPS, float, setFPS);
|
||||||
READ_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, float, setCurrentFrame);
|
READ_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, float, setCurrentFrame);
|
||||||
READ_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, bool, setRunning);
|
READ_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, bool, setRunning);
|
||||||
|
|
|
@ -85,6 +85,7 @@ public:
|
||||||
DEFINE_PROPERTY(PROP_ANIMATION_FIRST_FRAME, FirstFrame, firstFrame, float, 0.0f); // was animationSettings.firstFrame
|
DEFINE_PROPERTY(PROP_ANIMATION_FIRST_FRAME, FirstFrame, firstFrame, float, 0.0f); // was animationSettings.firstFrame
|
||||||
DEFINE_PROPERTY(PROP_ANIMATION_LAST_FRAME, LastFrame, lastFrame, float, MAXIMUM_POSSIBLE_FRAME); // was animationSettings.lastFrame
|
DEFINE_PROPERTY(PROP_ANIMATION_LAST_FRAME, LastFrame, lastFrame, float, MAXIMUM_POSSIBLE_FRAME); // was animationSettings.lastFrame
|
||||||
DEFINE_PROPERTY(PROP_ANIMATION_HOLD, Hold, hold, bool, false); // was animationSettings.hold
|
DEFINE_PROPERTY(PROP_ANIMATION_HOLD, Hold, hold, bool, false); // was animationSettings.hold
|
||||||
|
DEFINE_PROPERTY(PROP_ANIMATION_ALLOW_TRANSLATION, AllowTranslation, allowTranslation, bool, true);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend bool operator==(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b);
|
friend bool operator==(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b);
|
||||||
|
|
|
@ -1033,6 +1033,7 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue
|
||||||
ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_FIRST_FRAME, Animation, animation, FirstFrame, firstFrame);
|
ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_FIRST_FRAME, Animation, animation, FirstFrame, firstFrame);
|
||||||
ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_LAST_FRAME, Animation, animation, LastFrame, lastFrame);
|
ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_LAST_FRAME, Animation, animation, LastFrame, lastFrame);
|
||||||
ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_HOLD, Animation, animation, Hold, hold);
|
ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_HOLD, Animation, animation, Hold, hold);
|
||||||
|
ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_ALLOW_TRANSLATION, Animation, animation, AllowTranslation, allowTranslation);
|
||||||
|
|
||||||
ADD_GROUP_PROPERTY_TO_MAP(PROP_SKYBOX_COLOR, Skybox, skybox, Color, color);
|
ADD_GROUP_PROPERTY_TO_MAP(PROP_SKYBOX_COLOR, Skybox, skybox, Color, color);
|
||||||
ADD_GROUP_PROPERTY_TO_MAP(PROP_SKYBOX_URL, Skybox, skybox, URL, url);
|
ADD_GROUP_PROPERTY_TO_MAP(PROP_SKYBOX_URL, Skybox, skybox, URL, url);
|
||||||
|
|
|
@ -40,6 +40,7 @@ enum EntityPropertyList {
|
||||||
PROP_ANIMATION_FPS,
|
PROP_ANIMATION_FPS,
|
||||||
PROP_ANIMATION_FRAME_INDEX,
|
PROP_ANIMATION_FRAME_INDEX,
|
||||||
PROP_ANIMATION_PLAYING,
|
PROP_ANIMATION_PLAYING,
|
||||||
|
PROP_ANIMATION_ALLOW_TRANSLATION,
|
||||||
|
|
||||||
// these properties are supported by the EntityItem base class
|
// these properties are supported by the EntityItem base class
|
||||||
PROP_REGISTRATION_POINT,
|
PROP_REGISTRATION_POINT,
|
||||||
|
|
|
@ -330,6 +330,10 @@ void ModelEntityItem::setAnimationSettings(const QString& value) {
|
||||||
setAnimationHold(hold);
|
setAnimationHold(hold);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (settingsMap.contains("allowTranslation")) {
|
||||||
|
bool allowTranslation = settingsMap["allowTranslation"].toBool();
|
||||||
|
setAnimationAllowTranslation(allowTranslation);
|
||||||
|
}
|
||||||
_dirtyFlags |= Simulation::DIRTY_UPDATEABLE;
|
_dirtyFlags |= Simulation::DIRTY_UPDATEABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,10 @@ public:
|
||||||
|
|
||||||
void setAnimationCurrentFrame(float value);
|
void setAnimationCurrentFrame(float value);
|
||||||
void setAnimationIsPlaying(bool value);
|
void setAnimationIsPlaying(bool value);
|
||||||
void setAnimationFPS(float value);
|
void setAnimationFPS(float value);
|
||||||
|
|
||||||
|
void setAnimationAllowTranslation(bool value) { _animationProperties.setAllowTranslation(value); };
|
||||||
|
bool getAnimationAllowTranslation() const { return _animationProperties.getAllowTranslation(); };
|
||||||
|
|
||||||
void setAnimationLoop(bool loop);
|
void setAnimationLoop(bool loop);
|
||||||
bool getAnimationLoop() const;
|
bool getAnimationLoop() const;
|
||||||
|
|
|
@ -30,7 +30,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
||||||
case PacketType::EntityEdit:
|
case PacketType::EntityEdit:
|
||||||
case PacketType::EntityData:
|
case PacketType::EntityData:
|
||||||
case PacketType::EntityPhysics:
|
case PacketType::EntityPhysics:
|
||||||
return VERSION_ENTITIES_HAS_HIGHLIGHT_SCRIPTING_INTERFACE;
|
return VERSION_ENTITIES_ANIMATION_ALLOW_TRANSLATION_PROPERTIES;
|
||||||
case PacketType::EntityQuery:
|
case PacketType::EntityQuery:
|
||||||
return static_cast<PacketVersion>(EntityQueryPacketVersion::JSONFilterWithFamilyTree);
|
return static_cast<PacketVersion>(EntityQueryPacketVersion::JSONFilterWithFamilyTree);
|
||||||
case PacketType::AvatarIdentity:
|
case PacketType::AvatarIdentity:
|
||||||
|
|
|
@ -260,6 +260,7 @@ const PacketVersion VERSION_ENTITIES_HINGE_CONSTRAINT = 69;
|
||||||
const PacketVersion VERSION_ENTITIES_BULLET_DYNAMICS = 70;
|
const PacketVersion VERSION_ENTITIES_BULLET_DYNAMICS = 70;
|
||||||
const PacketVersion VERSION_ENTITIES_HAS_SHOULD_HIGHLIGHT = 71;
|
const PacketVersion VERSION_ENTITIES_HAS_SHOULD_HIGHLIGHT = 71;
|
||||||
const PacketVersion VERSION_ENTITIES_HAS_HIGHLIGHT_SCRIPTING_INTERFACE = 72;
|
const PacketVersion VERSION_ENTITIES_HAS_HIGHLIGHT_SCRIPTING_INTERFACE = 72;
|
||||||
|
const PacketVersion VERSION_ENTITIES_ANIMATION_ALLOW_TRANSLATION_PROPERTIES = 73;
|
||||||
|
|
||||||
enum class EntityQueryPacketVersion: PacketVersion {
|
enum class EntityQueryPacketVersion: PacketVersion {
|
||||||
JSONFilter = 18,
|
JSONFilter = 18,
|
||||||
|
|
|
@ -92,6 +92,7 @@ void EntityMotionState::updateServerPhysicsVariables() {
|
||||||
|
|
||||||
Transform localTransform;
|
Transform localTransform;
|
||||||
_entity->getLocalTransformAndVelocities(localTransform, _serverVelocity, _serverAngularVelocity);
|
_entity->getLocalTransformAndVelocities(localTransform, _serverVelocity, _serverAngularVelocity);
|
||||||
|
_serverVariablesSet = true;
|
||||||
_serverPosition = localTransform.getTranslation();
|
_serverPosition = localTransform.getTranslation();
|
||||||
_serverRotation = localTransform.getRotation();
|
_serverRotation = localTransform.getRotation();
|
||||||
_serverAcceleration = _entity->getAcceleration();
|
_serverAcceleration = _entity->getAcceleration();
|
||||||
|
@ -99,18 +100,19 @@ void EntityMotionState::updateServerPhysicsVariables() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityMotionState::handleDeactivation() {
|
void EntityMotionState::handleDeactivation() {
|
||||||
// copy _server data to entity
|
if (_serverVariablesSet) {
|
||||||
bool success;
|
// copy _server data to entity
|
||||||
_entity->setPosition(_serverPosition, success, false);
|
Transform localTransform = _entity->getLocalTransform();
|
||||||
_entity->setOrientation(_serverRotation, success, false);
|
localTransform.setTranslation(_serverPosition);
|
||||||
_entity->setVelocity(ENTITY_ITEM_ZERO_VEC3);
|
localTransform.setRotation(_serverRotation);
|
||||||
_entity->setAngularVelocity(ENTITY_ITEM_ZERO_VEC3);
|
_entity->setLocalTransformAndVelocities(localTransform, ENTITY_ITEM_ZERO_VEC3, ENTITY_ITEM_ZERO_VEC3);
|
||||||
// and also to RigidBody
|
// and also to RigidBody
|
||||||
btTransform worldTrans;
|
btTransform worldTrans;
|
||||||
worldTrans.setOrigin(glmToBullet(_serverPosition));
|
worldTrans.setOrigin(glmToBullet(_entity->getPosition()));
|
||||||
worldTrans.setRotation(glmToBullet(_serverRotation));
|
worldTrans.setRotation(glmToBullet(_entity->getRotation()));
|
||||||
_body->setWorldTransform(worldTrans);
|
_body->setWorldTransform(worldTrans);
|
||||||
// no need to update velocities... should already be zero
|
// no need to update velocities... should already be zero
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// virtual
|
// 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 we've never checked before, our _lastStep will be 0, and we need to initialize our state
|
||||||
if (_lastStep == 0) {
|
if (_lastStep == 0) {
|
||||||
btTransform xform = _body->getWorldTransform();
|
btTransform xform = _body->getWorldTransform();
|
||||||
|
_serverVariablesSet = true;
|
||||||
_serverPosition = worldToLocal.transform(bulletToGLM(xform.getOrigin()));
|
_serverPosition = worldToLocal.transform(bulletToGLM(xform.getOrigin()));
|
||||||
_serverRotation = worldToLocal.getRotation() * bulletToGLM(xform.getRotation());
|
_serverRotation = worldToLocal.getRotation() * bulletToGLM(xform.getRotation());
|
||||||
_serverVelocity = worldVelocityToLocal.transform(getBodyLinearVelocityGTSigma());
|
_serverVelocity = worldVelocityToLocal.transform(getBodyLinearVelocityGTSigma());
|
||||||
|
|
|
@ -107,6 +107,7 @@ protected:
|
||||||
// Meanwhile we also keep a raw EntityItem* for internal stuff where the pointer is guaranteed valid.
|
// Meanwhile we also keep a raw EntityItem* for internal stuff where the pointer is guaranteed valid.
|
||||||
EntityItem* _entity;
|
EntityItem* _entity;
|
||||||
|
|
||||||
|
bool _serverVariablesSet { false };
|
||||||
glm::vec3 _serverPosition; // in simulation-frame (not world-frame)
|
glm::vec3 _serverPosition; // in simulation-frame (not world-frame)
|
||||||
glm::quat _serverRotation;
|
glm::quat _serverRotation;
|
||||||
glm::vec3 _serverVelocity;
|
glm::vec3 _serverVelocity;
|
||||||
|
|
|
@ -827,10 +827,10 @@ AnimationDetails::AnimationDetails() :
|
||||||
}
|
}
|
||||||
|
|
||||||
AnimationDetails::AnimationDetails(QString role, QUrl url, float fps, float priority, bool loop,
|
AnimationDetails::AnimationDetails(QString role, QUrl url, float fps, float priority, bool loop,
|
||||||
bool hold, bool startAutomatically, float firstFrame, float lastFrame, bool running, float currentFrame) :
|
bool hold, bool startAutomatically, float firstFrame, float lastFrame, bool running, float currentFrame, bool allowTranslation) :
|
||||||
role(role), url(url), fps(fps), priority(priority), loop(loop), hold(hold),
|
role(role), url(url), fps(fps), priority(priority), loop(loop), hold(hold),
|
||||||
startAutomatically(startAutomatically), firstFrame(firstFrame), lastFrame(lastFrame),
|
startAutomatically(startAutomatically), firstFrame(firstFrame), lastFrame(lastFrame),
|
||||||
running(running), currentFrame(currentFrame) {
|
running(running), currentFrame(currentFrame), allowTranslation(allowTranslation) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -847,6 +847,7 @@ QScriptValue animationDetailsToScriptValue(QScriptEngine* engine, const Animatio
|
||||||
obj.setProperty("lastFrame", details.lastFrame);
|
obj.setProperty("lastFrame", details.lastFrame);
|
||||||
obj.setProperty("running", details.running);
|
obj.setProperty("running", details.running);
|
||||||
obj.setProperty("currentFrame", details.currentFrame);
|
obj.setProperty("currentFrame", details.currentFrame);
|
||||||
|
obj.setProperty("allowTranslation", details.allowTranslation);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -197,7 +197,7 @@ class AnimationDetails {
|
||||||
public:
|
public:
|
||||||
AnimationDetails();
|
AnimationDetails();
|
||||||
AnimationDetails(QString role, QUrl url, float fps, float priority, bool loop,
|
AnimationDetails(QString role, QUrl url, float fps, float priority, bool loop,
|
||||||
bool hold, bool startAutomatically, float firstFrame, float lastFrame, bool running, float currentFrame);
|
bool hold, bool startAutomatically, float firstFrame, float lastFrame, bool running, float currentFrame, bool allowTranslation);
|
||||||
|
|
||||||
QString role;
|
QString role;
|
||||||
QUrl url;
|
QUrl url;
|
||||||
|
@ -210,6 +210,7 @@ public:
|
||||||
float lastFrame;
|
float lastFrame;
|
||||||
bool running;
|
bool running;
|
||||||
float currentFrame;
|
float currentFrame;
|
||||||
|
bool allowTranslation;
|
||||||
};
|
};
|
||||||
Q_DECLARE_METATYPE(AnimationDetails);
|
Q_DECLARE_METATYPE(AnimationDetails);
|
||||||
QScriptValue animationDetailsToScriptValue(QScriptEngine* engine, const AnimationDetails& event);
|
QScriptValue animationDetailsToScriptValue(QScriptEngine* engine, const AnimationDetails& event);
|
||||||
|
|
|
@ -731,7 +731,7 @@ void SpatiallyNestable::setScale(float value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const Transform SpatiallyNestable::getLocalTransform() const {
|
Transform SpatiallyNestable::getLocalTransform() const {
|
||||||
Transform result;
|
Transform result;
|
||||||
_transformLock.withReadLock([&] {
|
_transformLock.withReadLock([&] {
|
||||||
result =_transform;
|
result =_transform;
|
||||||
|
|
|
@ -121,7 +121,7 @@ public:
|
||||||
virtual glm::vec3 getScale(int jointIndex) const;
|
virtual glm::vec3 getScale(int jointIndex) const;
|
||||||
|
|
||||||
// object's parent's frame
|
// object's parent's frame
|
||||||
virtual const Transform getLocalTransform() const;
|
virtual Transform getLocalTransform() const;
|
||||||
virtual void setLocalTransform(const Transform& transform);
|
virtual void setLocalTransform(const Transform& transform);
|
||||||
|
|
||||||
virtual glm::vec3 getLocalPosition() const;
|
virtual glm::vec3 getLocalPosition() const;
|
||||||
|
|
|
@ -24,13 +24,6 @@ namespace Cursor {
|
||||||
return _icon;
|
return _icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class MouseInstance : public Instance {
|
|
||||||
Source getType() const override {
|
|
||||||
return Source::MOUSE;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
QMap<uint16_t, QString> Manager::ICON_NAMES {
|
QMap<uint16_t, QString> Manager::ICON_NAMES {
|
||||||
{ Icon::SYSTEM, "SYSTEM", },
|
{ Icon::SYSTEM, "SYSTEM", },
|
||||||
{ Icon::DEFAULT, "DEFAULT", },
|
{ Icon::DEFAULT, "DEFAULT", },
|
||||||
|
@ -38,7 +31,7 @@ namespace Cursor {
|
||||||
{ Icon::ARROW, "ARROW", },
|
{ Icon::ARROW, "ARROW", },
|
||||||
{ Icon::RETICLE, "RETICLE", },
|
{ Icon::RETICLE, "RETICLE", },
|
||||||
};
|
};
|
||||||
QMap<uint16_t, QString> Manager::ICONS;
|
|
||||||
static uint16_t _customIconId = Icon::USER_BASE;
|
static uint16_t _customIconId = Icon::USER_BASE;
|
||||||
|
|
||||||
Manager::Manager() {
|
Manager::Manager() {
|
||||||
|
@ -62,8 +55,8 @@ namespace Cursor {
|
||||||
}
|
}
|
||||||
|
|
||||||
Manager& Manager::instance() {
|
Manager& Manager::instance() {
|
||||||
static Manager instance;
|
static QSharedPointer<Manager> instance = DependencyManager::get<Cursor::Manager>();
|
||||||
return instance;
|
return *instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<uint16_t> Manager::registeredIcons() const {
|
QList<uint16_t> Manager::registeredIcons() const {
|
||||||
|
@ -76,7 +69,6 @@ namespace Cursor {
|
||||||
|
|
||||||
Instance* Manager::getCursor(uint8_t index) {
|
Instance* Manager::getCursor(uint8_t index) {
|
||||||
Q_ASSERT(index < getCount());
|
Q_ASSERT(index < getCount());
|
||||||
static MouseInstance mouseInstance;
|
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
return &mouseInstance;
|
return &mouseInstance;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <DependencyManager.h>
|
||||||
|
|
||||||
#include <GLMHelpers.h>
|
#include <GLMHelpers.h>
|
||||||
|
|
||||||
|
@ -39,7 +40,15 @@ namespace Cursor {
|
||||||
uint16_t _icon;
|
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();
|
||||||
Manager(const Manager& other) = delete;
|
Manager(const Manager& other) = delete;
|
||||||
public:
|
public:
|
||||||
|
@ -52,12 +61,13 @@ namespace Cursor {
|
||||||
QList<uint16_t> registeredIcons() const;
|
QList<uint16_t> registeredIcons() const;
|
||||||
const QString& getIconImage(uint16_t icon);
|
const QString& getIconImage(uint16_t icon);
|
||||||
|
|
||||||
static QMap<uint16_t, QString> ICONS;
|
|
||||||
static QMap<uint16_t, QString> ICON_NAMES;
|
static QMap<uint16_t, QString> ICON_NAMES;
|
||||||
static Icon lookupIcon(const QString& name);
|
static Icon lookupIcon(const QString& name);
|
||||||
static const QString& getIconName(const Icon& icon);
|
static const QString& getIconName(const Icon& icon);
|
||||||
private:
|
private:
|
||||||
|
MouseInstance mouseInstance;
|
||||||
float _scale{ 1.0f };
|
float _scale{ 1.0f };
|
||||||
|
QMap<uint16_t, QString> ICONS;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
var isHmdPreviewDisabled = true;
|
var isHmdPreviewDisabled = true;
|
||||||
function fromQml(message) {
|
function fromQml(message) {
|
||||||
switch (message.method) {
|
switch (message.method) {
|
||||||
|
case 'passphrasePopup_cancelClicked':
|
||||||
case 'walletSetup_cancelClicked':
|
case 'walletSetup_cancelClicked':
|
||||||
case 'needsLogIn_cancelClicked':
|
case 'needsLogIn_cancelClicked':
|
||||||
tablet.gotoHomeScreen();
|
tablet.gotoHomeScreen();
|
||||||
|
|
|
@ -446,6 +446,10 @@
|
||||||
<input type="checkbox" id="property-model-animation-hold">
|
<input type="checkbox" id="property-model-animation-hold">
|
||||||
<label for="property-model-animation-hold">Animation hold</label>
|
<label for="property-model-animation-hold">Animation hold</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="property checkbox indent">
|
||||||
|
<input type="checkbox" id="property-model-animation-allow-translation">
|
||||||
|
<label for="property-model-animation-allow-translation">Animation Allow Translation</label>
|
||||||
|
</div>
|
||||||
<div id="animation-fps" class="property number">
|
<div id="animation-fps" class="property number">
|
||||||
<label>Animation FPS</label>
|
<label>Animation FPS</label>
|
||||||
<input type="number" id="property-model-animation-fps">
|
<input type="number" id="property-model-animation-fps">
|
||||||
|
@ -642,10 +646,6 @@
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<fieldset id="polyvox" class="major">
|
<fieldset id="polyvox" class="major">
|
||||||
<legend class="section-header spatial-group poly-vox-section property xyz">
|
<legend class="section-header spatial-group poly-vox-section property xyz">
|
||||||
Voxel volume size <span>m</span>
|
Voxel volume size <span>m</span>
|
||||||
|
|
|
@ -611,6 +611,7 @@ function loaded() {
|
||||||
var elModelAnimationLastFrame = document.getElementById("property-model-animation-last-frame");
|
var elModelAnimationLastFrame = document.getElementById("property-model-animation-last-frame");
|
||||||
var elModelAnimationLoop = document.getElementById("property-model-animation-loop");
|
var elModelAnimationLoop = document.getElementById("property-model-animation-loop");
|
||||||
var elModelAnimationHold = document.getElementById("property-model-animation-hold");
|
var elModelAnimationHold = document.getElementById("property-model-animation-hold");
|
||||||
|
var elModelAnimationAllowTranslation = document.getElementById("property-model-animation-allow-translation");
|
||||||
var elModelTextures = document.getElementById("property-model-textures");
|
var elModelTextures = document.getElementById("property-model-textures");
|
||||||
var elModelOriginalTextures = document.getElementById("property-model-original-textures");
|
var elModelOriginalTextures = document.getElementById("property-model-original-textures");
|
||||||
|
|
||||||
|
@ -926,6 +927,7 @@ function loaded() {
|
||||||
elModelAnimationLastFrame.value = properties.animation.lastFrame;
|
elModelAnimationLastFrame.value = properties.animation.lastFrame;
|
||||||
elModelAnimationLoop.checked = properties.animation.loop;
|
elModelAnimationLoop.checked = properties.animation.loop;
|
||||||
elModelAnimationHold.checked = properties.animation.hold;
|
elModelAnimationHold.checked = properties.animation.hold;
|
||||||
|
elModelAnimationAllowTranslation.checked = properties.animation.allowTranslation;
|
||||||
elModelTextures.value = properties.textures;
|
elModelTextures.value = properties.textures;
|
||||||
setTextareaScrolling(elModelTextures);
|
setTextareaScrolling(elModelTextures);
|
||||||
elModelOriginalTextures.value = properties.originalTextures;
|
elModelOriginalTextures.value = properties.originalTextures;
|
||||||
|
@ -1276,6 +1278,7 @@ function loaded() {
|
||||||
elModelAnimationLastFrame.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('animation', 'lastFrame'));
|
elModelAnimationLastFrame.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('animation', 'lastFrame'));
|
||||||
elModelAnimationLoop.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('animation', 'loop'));
|
elModelAnimationLoop.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('animation', 'loop'));
|
||||||
elModelAnimationHold.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('animation', 'hold'));
|
elModelAnimationHold.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('animation', 'hold'));
|
||||||
|
elModelAnimationAllowTranslation.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('animation', 'allowTranslation'));
|
||||||
|
|
||||||
elModelTextures.addEventListener('change', createEmitTextPropertyUpdateFunction('textures'));
|
elModelTextures.addEventListener('change', createEmitTextPropertyUpdateFunction('textures'));
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
var isPreparing = false; // Explicitly track download request status.
|
var isPreparing = false; // Explicitly track download request status.
|
||||||
|
|
||||||
var confirmAllPurchases = false; // Set this to "true" to cause Checkout.qml to popup for all items, even if free
|
var confirmAllPurchases = false; // Set this to "true" to cause Checkout.qml to popup for all items, even if free
|
||||||
|
|
||||||
function injectCommonCode(isDirectoryPage) {
|
function injectCommonCode(isDirectoryPage) {
|
||||||
|
|
||||||
// Supporting styles from marketplaces.css.
|
// Supporting styles from marketplaces.css.
|
||||||
|
@ -122,7 +122,7 @@
|
||||||
|
|
||||||
function injectBuyButtonOnMainPage() {
|
function injectBuyButtonOnMainPage() {
|
||||||
var cost;
|
var cost;
|
||||||
|
|
||||||
$('.grid-item').find('#price-or-edit').find('a').each(function() {
|
$('.grid-item').find('#price-or-edit').find('a').each(function() {
|
||||||
$(this).attr('data-href', $(this).attr('href'));
|
$(this).attr('data-href', $(this).attr('href'));
|
||||||
$(this).attr('href', '#');
|
$(this).attr('href', '#');
|
||||||
|
@ -130,16 +130,16 @@
|
||||||
|
|
||||||
$(this).closest('.col-xs-3').prev().attr("class", 'col-xs-6');
|
$(this).closest('.col-xs-3').prev().attr("class", 'col-xs-6');
|
||||||
$(this).closest('.col-xs-3').attr("class", 'col-xs-6');
|
$(this).closest('.col-xs-3').attr("class", 'col-xs-6');
|
||||||
|
|
||||||
if (parseInt(cost) > 0) {
|
if (parseInt(cost) > 0) {
|
||||||
var priceElement = $(this).find('.price')
|
var priceElement = $(this).find('.price')
|
||||||
priceElement.css({ "width": "auto", "padding": "3px 5px", "height": "26px" });
|
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 });
|
priceElement.css({ "min-width": priceElement.width() + 10 });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
$('.grid-item').find('#price-or-edit').find('a').on('click', function () {
|
$('.grid-item').find('#price-or-edit').find('a').on('click', function () {
|
||||||
buyButtonClicked($(this).closest('.grid-item').attr('data-item-id'),
|
buyButtonClicked($(this).closest('.grid-item').attr('data-item-id'),
|
||||||
$(this).closest('.grid-item').find('.item-title').text(),
|
$(this).closest('.grid-item').find('.item-title').text(),
|
||||||
|
@ -175,11 +175,12 @@
|
||||||
if (confirmAllPurchases) {
|
if (confirmAllPurchases) {
|
||||||
var href = $('#side-info').find('.btn').first().attr('href');
|
var href = $('#side-info').find('.btn').first().attr('href');
|
||||||
$('#side-info').find('.btn').first().attr('href', '#');
|
$('#side-info').find('.btn').first().attr('href', '#');
|
||||||
|
|
||||||
var cost = $('.item-cost').text();
|
var cost = $('.item-cost').text();
|
||||||
|
|
||||||
if (parseInt(cost) > 0 && $('#side-info').find('#buyItemButton').size() === 0) {
|
if (parseInt(cost) > 0 && $('#side-info').find('#buyItemButton').size() === 0) {
|
||||||
$('#side-info').find('.btn').first().html('<span class="glyphicon glyphicon-download" id="buyItemButton"></span>Own Item: ' + (parseFloat(cost / 100).toFixed(2)) + ' HFC');
|
$('#side-info').find('.btn').first().html('<span class="glyphicon glyphicon-download" id="buyItemButton"></span>Own Item: ' + cost + ' HFC');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#side-info').find('.btn').first().on('click', function () {
|
$('#side-info').find('.btn').first().on('click', function () {
|
||||||
|
@ -264,7 +265,7 @@
|
||||||
// Reference: https://clara.io/learn/sdk/api/export
|
// Reference: https://clara.io/learn/sdk/api/export
|
||||||
|
|
||||||
//var XMLHTTPREQUEST_URL = "https://clara.io/api/scenes/{uuid}/export/fbx?zip=true¢erScene=true&alignSceneGround=true&fbxUnit=Meter&fbxVersion=7&fbxEmbedTextures=true&imageFormat=WebGL";
|
//var XMLHTTPREQUEST_URL = "https://clara.io/api/scenes/{uuid}/export/fbx?zip=true¢erScene=true&alignSceneGround=true&fbxUnit=Meter&fbxVersion=7&fbxEmbedTextures=true&imageFormat=WebGL";
|
||||||
// 13 Jan 2017: Specify FBX version 5 and remove some options in order to make Clara.io site more likely to
|
// 13 Jan 2017: Specify FBX version 5 and remove some options in order to make Clara.io site more likely to
|
||||||
// be successful in generating zip files.
|
// be successful in generating zip files.
|
||||||
var XMLHTTPREQUEST_URL = "https://clara.io/api/scenes/{uuid}/export/fbx?fbxUnit=Meter&fbxVersion=5&fbxEmbedTextures=true&imageFormat=WebGL";
|
var XMLHTTPREQUEST_URL = "https://clara.io/api/scenes/{uuid}/export/fbx?fbxUnit=Meter&fbxVersion=5&fbxEmbedTextures=true&imageFormat=WebGL";
|
||||||
|
|
||||||
|
@ -447,7 +448,7 @@
|
||||||
cancelClaraDownload();
|
cancelClaraDownload();
|
||||||
} else {
|
} else {
|
||||||
var parsedJsonMessage = JSON.parse(message);
|
var parsedJsonMessage = JSON.parse(message);
|
||||||
|
|
||||||
if (parsedJsonMessage.type === "marketplaces") {
|
if (parsedJsonMessage.type === "marketplaces") {
|
||||||
if (parsedJsonMessage.action === "inspectionModeSetting") {
|
if (parsedJsonMessage.action === "inspectionModeSetting") {
|
||||||
confirmAllPurchases = !!parsedJsonMessage.data;
|
confirmAllPurchases = !!parsedJsonMessage.data;
|
||||||
|
|
|
@ -197,6 +197,7 @@
|
||||||
// Description:
|
// Description:
|
||||||
// -Called when a message is received from Checkout.qml. The "message" argument is what is sent from the Checkout QML
|
// -Called when a message is received from Checkout.qml. The "message" argument is what is sent from the Checkout QML
|
||||||
// in the format "{method, params}", like json-rpc.
|
// in the format "{method, params}", like json-rpc.
|
||||||
|
var isHmdPreviewDisabled = true;
|
||||||
function fromQml(message) {
|
function fromQml(message) {
|
||||||
switch (message.method) {
|
switch (message.method) {
|
||||||
case 'checkout_setUpClicked':
|
case 'checkout_setUpClicked':
|
||||||
|
@ -231,12 +232,20 @@
|
||||||
case 'purchases_goToMarketplaceClicked':
|
case 'purchases_goToMarketplaceClicked':
|
||||||
tablet.gotoWebScreen(MARKETPLACE_URL_INITIAL, MARKETPLACES_INJECT_SCRIPT_URL);
|
tablet.gotoWebScreen(MARKETPLACE_URL_INITIAL, MARKETPLACES_INJECT_SCRIPT_URL);
|
||||||
break;
|
break;
|
||||||
|
case 'passphrasePopup_cancelClicked':
|
||||||
case 'needsLogIn_cancelClicked':
|
case 'needsLogIn_cancelClicked':
|
||||||
tablet.gotoWebScreen(MARKETPLACE_URL_INITIAL, MARKETPLACES_INJECT_SCRIPT_URL);
|
tablet.gotoWebScreen(MARKETPLACE_URL_INITIAL, MARKETPLACES_INJECT_SCRIPT_URL);
|
||||||
break;
|
break;
|
||||||
case 'needsLogIn_loginClicked':
|
case 'needsLogIn_loginClicked':
|
||||||
openLoginWindow();
|
openLoginWindow();
|
||||||
break;
|
break;
|
||||||
|
case 'disableHmdPreview':
|
||||||
|
isHmdPreviewDisabled = Menu.isOptionChecked("Disable Preview");
|
||||||
|
Menu.setIsOptionChecked("Disable Preview", true);
|
||||||
|
break;
|
||||||
|
case 'maybeEnableHmdPreview':
|
||||||
|
Menu.setIsOptionChecked("Disable Preview", isHmdPreviewDisabled);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
print('Unrecognized message from Checkout.qml or Purchases.qml: ' + JSON.stringify(message));
|
print('Unrecognized message from Checkout.qml or Purchases.qml: ' + JSON.stringify(message));
|
||||||
}
|
}
|
||||||
|
|
168
unpublishedScripts/marketplace/dodgeBall/dodgeBall.js
Normal file
168
unpublishedScripts/marketplace/dodgeBall/dodgeBall.js
Normal 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();
|
||||||
|
};
|
||||||
|
|
||||||
|
});
|
Loading…
Reference in a new issue