mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-08 20:22:22 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into feature/ant-man
This commit is contained in:
commit
fec8482b69
46 changed files with 1082 additions and 640 deletions
|
@ -35,7 +35,7 @@ void ScriptableAvatar::startAnimation(const QString& url, float fps, float prior
|
|||
return;
|
||||
}
|
||||
_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;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,14 @@
|
|||
<title>Welcome to Interface</title>
|
||||
|
||||
<style>
|
||||
body {
|
||||
@font-face {
|
||||
font-family: 'Raleway Light';
|
||||
src: url('../fonts/Raleway-Light.ttf') format('truetype');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
body {
|
||||
background: black;
|
||||
width: 100%;
|
||||
overflow-x: hidden;
|
||||
|
@ -15,6 +22,14 @@
|
|||
padding: 0;
|
||||
}
|
||||
|
||||
a:link {color:inherit}
|
||||
a:active {color:inherit}
|
||||
a:visited {color:inherit}
|
||||
a:hover {
|
||||
color:inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#left_button {
|
||||
position: absolute;
|
||||
left: 70;
|
||||
|
@ -38,6 +53,15 @@
|
|||
position: absolute;
|
||||
top: 0; left: 0; bottom: 0; right: 0;
|
||||
}
|
||||
|
||||
#report_problem {
|
||||
position: fixed;
|
||||
top: 10;
|
||||
right: 10;
|
||||
font-family: "Raleway Light", sans-serif;
|
||||
text-decoration: none;
|
||||
color: #ddd;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
var handControllerImageURL = null;
|
||||
|
@ -152,6 +176,7 @@
|
|||
<a href="#" id="left_button" onmousedown="cycleLeft()"></a>
|
||||
<a href="#" id="right_button" onmousedown="cycleRight()"></a>
|
||||
</div>
|
||||
<a href="mailto:support@highfidelity.com" id="report_problem">Report Problem</a>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
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 |
|
@ -29,7 +29,6 @@ Rectangle {
|
|||
property bool purchasesReceived: false;
|
||||
property bool balanceReceived: false;
|
||||
property bool securityImageResultReceived: false;
|
||||
property bool keyFilePathIfExistsResultReceived: false;
|
||||
property string itemId: "";
|
||||
property string itemHref: "";
|
||||
property double balanceAfterPurchase: 0;
|
||||
|
@ -46,10 +45,15 @@ Rectangle {
|
|||
root.activeView = "needsLogIn";
|
||||
} else if (isLoggedIn) {
|
||||
root.activeView = "initialize";
|
||||
commerce.getSecurityImage();
|
||||
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;
|
||||
if (!exists && root.activeView !== "notSetUp") { // "If security image is not set up"
|
||||
root.activeView = "notSetUp";
|
||||
} else if (root.securityImageResultReceived && exists && root.keyFilePathIfExistsResultReceived && root.activeView === "initialize") {
|
||||
root.activeView = "checkoutMain";
|
||||
} else if (exists && root.activeView === "initialize") {
|
||||
commerce.getWalletAuthenticatedStatus();
|
||||
} else if (exists) {
|
||||
// just set the source again (to be sure the change was noticed)
|
||||
securityImage.source = "";
|
||||
|
@ -66,12 +70,17 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
|
||||
onKeyFilePathIfExistsResult: {
|
||||
keyFilePathIfExistsResultReceived = true;
|
||||
if (path === "" && root.activeView !== "notSetUp") {
|
||||
root.activeView = "notSetUp";
|
||||
} else if (root.securityImageResultReceived && root.keyFilePathIfExistsResultReceived && path !== "" && root.activeView === "initialize") {
|
||||
onWalletAuthenticatedStatusResult: {
|
||||
if (!isAuthenticated && !passphraseModal.visible) {
|
||||
passphraseModal.visible = true;
|
||||
} else if (isAuthenticated) {
|
||||
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);
|
||||
} else {
|
||||
root.balanceReceived = true;
|
||||
hfcBalanceText.text = (parseFloat(result.data.balance/100).toFixed(2)) + " HFC";
|
||||
balanceAfterPurchase = parseFloat(result.data.balance/100) - root.itemPriceFull/100;
|
||||
hfcBalanceText.text = result.data.balance + " HFC";
|
||||
balanceAfterPurchase = result.data.balance - root.itemPriceFull;
|
||||
root.setBuyText();
|
||||
}
|
||||
}
|
||||
|
@ -110,10 +119,6 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
|
||||
HifiWallet.SecurityImageModel {
|
||||
id: securityImageModel;
|
||||
}
|
||||
|
||||
//
|
||||
// TITLE BAR START
|
||||
//
|
||||
|
@ -195,7 +200,6 @@ Rectangle {
|
|||
securityImageResultReceived = false;
|
||||
purchasesReceived = false;
|
||||
balanceReceived = false;
|
||||
keyFilePathIfExistsResultReceived = false;
|
||||
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
|
||||
|
@ -553,7 +570,7 @@ Rectangle {
|
|||
}
|
||||
RalewayRegular {
|
||||
id: balanceAfterPurchaseText;
|
||||
text: balanceAfterPurchase.toFixed(2) + " HFC";
|
||||
text: balanceAfterPurchase + " HFC";
|
||||
// Text size
|
||||
size: balanceAfterPurchaseTextLabel.size;
|
||||
// Anchors
|
||||
|
@ -648,7 +665,7 @@ Rectangle {
|
|||
sendToScript({method: 'checkout_goToPurchases'});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RalewayRegular {
|
||||
id: buyText;
|
||||
// Text size
|
||||
|
@ -687,7 +704,7 @@ Rectangle {
|
|||
anchors.bottom: root.bottom;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
|
||||
|
||||
RalewayRegular {
|
||||
id: completeText;
|
||||
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;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
}
|
||||
|
||||
|
||||
Item {
|
||||
id: checkoutSuccessActionButtonsContainer;
|
||||
// Size
|
||||
|
@ -756,7 +773,7 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Item {
|
||||
id: continueShoppingButtonContainer;
|
||||
// Size
|
||||
|
@ -799,7 +816,7 @@ Rectangle {
|
|||
anchors.bottom: root.bottom;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
|
||||
|
||||
RalewayRegular {
|
||||
id: failureHeaderText;
|
||||
text: "<b>Purchase Failed.</b><br>Your Purchases and HFC balance haven't changed.";
|
||||
|
@ -818,7 +835,7 @@ Rectangle {
|
|||
horizontalAlignment: Text.AlignHCenter;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
}
|
||||
|
||||
|
||||
RalewayRegular {
|
||||
id: failureErrorText;
|
||||
// Text size
|
||||
|
@ -836,7 +853,7 @@ Rectangle {
|
|||
horizontalAlignment: Text.AlignHCenter;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
}
|
||||
|
||||
|
||||
Item {
|
||||
id: backToMarketplaceButtonContainer;
|
||||
// Size
|
||||
|
@ -892,7 +909,7 @@ Rectangle {
|
|||
itemNameText.text = message.params.itemName;
|
||||
itemAuthorText.text = message.params.itemAuthor;
|
||||
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;
|
||||
if (itemHref.indexOf('.json') === -1) {
|
||||
root.itemIsJson = false;
|
||||
|
|
|
@ -28,7 +28,6 @@ Rectangle {
|
|||
property string activeView: "initialize";
|
||||
property string referrerURL: "";
|
||||
property bool securityImageResultReceived: false;
|
||||
property bool keyFilePathIfExistsResultReceived: false;
|
||||
property bool purchasesReceived: false;
|
||||
property bool punctuationMode: false;
|
||||
// Style
|
||||
|
@ -41,9 +40,15 @@ Rectangle {
|
|||
root.activeView = "needsLogIn";
|
||||
} else if (isLoggedIn) {
|
||||
root.activeView = "initialize";
|
||||
commerce.getSecurityImage();
|
||||
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;
|
||||
if (!exists && root.activeView !== "notSetUp") { // "If security image is not set up"
|
||||
root.activeView = "notSetUp";
|
||||
} else if (root.securityImageResultReceived && exists && root.keyFilePathIfExistsResultReceived && root.activeView === "initialize") {
|
||||
root.activeView = "purchasesMain";
|
||||
} else if (exists && root.activeView === "initialize") {
|
||||
commerce.getWalletAuthenticatedStatus();
|
||||
} else if (exists) {
|
||||
// just set the source again (to be sure the change was noticed)
|
||||
securityImage.source = "";
|
||||
|
@ -60,12 +65,12 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
|
||||
onKeyFilePathIfExistsResult: {
|
||||
keyFilePathIfExistsResultReceived = true;
|
||||
if (path === "" && root.activeView !== "notSetUp") {
|
||||
root.activeView = "notSetUp";
|
||||
} else if (root.securityImageResultReceived && root.keyFilePathIfExistsResultReceived && path !== "" && root.activeView === "initialize") {
|
||||
onWalletAuthenticatedStatusResult: {
|
||||
if (!isAuthenticated && !passphraseModal.visible) {
|
||||
passphraseModal.visible = true;
|
||||
} else if (isAuthenticated) {
|
||||
root.activeView = "purchasesMain";
|
||||
commerce.inventory();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -166,7 +171,6 @@ Rectangle {
|
|||
Component.onCompleted: {
|
||||
securityImageResultReceived = false;
|
||||
purchasesReceived = false;
|
||||
keyFilePathIfExistsResultReceived = false;
|
||||
commerce.getLoginStatus();
|
||||
}
|
||||
}
|
||||
|
@ -191,6 +195,21 @@ Rectangle {
|
|||
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
|
||||
|
|
|
@ -47,11 +47,26 @@ Item {
|
|||
HifiControlsUit.Button {
|
||||
color: hifi.buttons.black;
|
||||
colorScheme: hifi.colorSchemes.dark;
|
||||
anchors.bottom: helpText.bottom;
|
||||
anchors.bottom: resetButton.top;
|
||||
anchors.bottomMargin: 15;
|
||||
anchors.horizontalCenter: parent.horizontalCenter;
|
||||
height: 50;
|
||||
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: {
|
||||
commerce.reset();
|
||||
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";
|
||||
}
|
||||
|
||||
onPassphraseSetupStatusResult: {
|
||||
sendMessageToLightbox({method: 'statusResult', status: passphraseIsSetup});
|
||||
onWalletAuthenticatedStatusResult: {
|
||||
sendMessageToLightbox({method: 'statusResult', status: isAuthenticated});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,10 +58,6 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
SecurityImageModel {
|
||||
id: gridModel;
|
||||
}
|
||||
|
||||
HifiControlsUit.TextField {
|
||||
id: passphraseField;
|
||||
anchors.top: parent.top;
|
||||
|
@ -199,7 +195,7 @@ Item {
|
|||
// Text below TextFields
|
||||
RalewaySemiBold {
|
||||
id: passwordReqs;
|
||||
text: "Passphrase must be at least 4 characters";
|
||||
text: "Passphrase must be at least 3 characters";
|
||||
// Text size
|
||||
size: 16;
|
||||
// Anchors
|
||||
|
@ -256,7 +252,7 @@ Item {
|
|||
}
|
||||
|
||||
function validateAndSubmitPassphrase() {
|
||||
if (passphraseField.text.length < 4) {
|
||||
if (passphraseField.text.length < 3) {
|
||||
setErrorText("Passphrase too short.");
|
||||
return false;
|
||||
} else if (passphraseField.text !== passphraseFieldAgain.text) {
|
||||
|
|
|
@ -26,8 +26,6 @@ Rectangle {
|
|||
id: root;
|
||||
|
||||
property string activeView: "initialize";
|
||||
property bool securityImageResultReceived: false;
|
||||
property bool keyFilePathIfExistsResultReceived: false;
|
||||
property bool keyboardRaised: false;
|
||||
|
||||
// Style
|
||||
|
@ -40,25 +38,30 @@ Rectangle {
|
|||
root.activeView = "needsLogIn";
|
||||
} else if (isLoggedIn) {
|
||||
root.activeView = "initialize";
|
||||
commerce.getSecurityImage();
|
||||
commerce.getKeyFilePathIfExists();
|
||||
}
|
||||
}
|
||||
|
||||
onSecurityImageResult: {
|
||||
securityImageResultReceived = true;
|
||||
if (!exists && root.activeView !== "notSetUp") { // "If security image is not set up"
|
||||
onKeyFilePathIfExistsResult: {
|
||||
if (path === "" && root.activeView !== "notSetUp") {
|
||||
root.activeView = "notSetUp";
|
||||
} else if (root.securityImageResultReceived && exists && root.keyFilePathIfExistsResultReceived && root.activeView === "initialize") {
|
||||
root.activeView = "walletHome";
|
||||
} else if (path !== "" && root.activeView === "initialize") {
|
||||
commerce.getSecurityImage();
|
||||
}
|
||||
}
|
||||
|
||||
onKeyFilePathIfExistsResult: {
|
||||
keyFilePathIfExistsResultReceived = true;
|
||||
if (path === "" && root.activeView !== "notSetUp") {
|
||||
onSecurityImageResult: {
|
||||
if (!exists && root.activeView !== "notSetUp") { // "If security image is not set up"
|
||||
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";
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +92,8 @@ Rectangle {
|
|||
if (msg.method === 'walletSetup_cancelClicked') {
|
||||
walletSetupLightbox.visible = false;
|
||||
} else if (msg.method === 'walletSetup_finished') {
|
||||
root.activeView = "walletHome";
|
||||
root.activeView = "initialize";
|
||||
commerce.getLoginStatus();
|
||||
} else if (msg.method === 'walletSetup_raiseKeyboard') {
|
||||
root.keyboardRaised = true;
|
||||
} 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 {
|
||||
id: notSetUp;
|
||||
visible: root.activeView === "notSetUp";
|
||||
|
|
|
@ -38,7 +38,7 @@ Item {
|
|||
}
|
||||
|
||||
onBalanceResult : {
|
||||
balanceText.text = parseFloat(result.data.balance/100).toFixed(2);
|
||||
balanceText.text = result.data.balance;
|
||||
}
|
||||
|
||||
onHistoryResult : {
|
||||
|
@ -88,13 +88,14 @@ Item {
|
|||
height: 60;
|
||||
Rectangle {
|
||||
id: hfcBalanceField;
|
||||
color: hifi.colors.darkGray;
|
||||
anchors.right: parent.right;
|
||||
anchors.left: parent.left;
|
||||
anchors.bottom: parent.bottom;
|
||||
height: parent.height - 15;
|
||||
|
||||
// "HFC" balance label
|
||||
RalewayRegular {
|
||||
FiraSansRegular {
|
||||
id: balanceLabel;
|
||||
text: "HFC";
|
||||
// Text size
|
||||
|
@ -106,7 +107,7 @@ Item {
|
|||
anchors.rightMargin: 4;
|
||||
width: paintedWidth;
|
||||
// Style
|
||||
color: hifi.colors.darkGray;
|
||||
color: hifi.colors.lightGrayText;
|
||||
// Alignment
|
||||
horizontalAlignment: Text.AlignRight;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
|
@ -121,7 +122,7 @@ Item {
|
|||
}
|
||||
|
||||
// Balance Text
|
||||
FiraSansRegular {
|
||||
FiraSansSemiBold {
|
||||
id: balanceText;
|
||||
text: "--";
|
||||
// Text size
|
||||
|
@ -133,7 +134,7 @@ Item {
|
|||
anchors.right: balanceLabel.left;
|
||||
anchors.rightMargin: 4;
|
||||
// Style
|
||||
color: hifi.colors.darkGray;
|
||||
color: hifi.colors.lightGrayText;
|
||||
// Alignment
|
||||
horizontalAlignment: Text.AlignRight;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
|
@ -258,7 +259,7 @@ Item {
|
|||
delegate: Item {
|
||||
width: parent.width;
|
||||
height: transactionText.height + 30;
|
||||
RalewayRegular {
|
||||
FiraSansRegular {
|
||||
id: transactionText;
|
||||
text: model.text;
|
||||
// Style
|
||||
|
@ -272,7 +273,7 @@ Item {
|
|||
horizontalAlignment: Text.AlignLeft;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
}
|
||||
|
||||
|
||||
HifiControlsUit.Separator {
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
|
@ -288,7 +289,7 @@ Item {
|
|||
}
|
||||
|
||||
// This should never be visible (since you immediately get 100 HFC)
|
||||
RalewayRegular {
|
||||
FiraSansRegular {
|
||||
id: emptyTransationHistory;
|
||||
size: 24;
|
||||
visible: !transactionHistory.visible && root.historyReceived;
|
||||
|
|
|
@ -39,9 +39,9 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
|
||||
onPassphraseSetupStatusResult: {
|
||||
onWalletAuthenticatedStatusResult: {
|
||||
securityImageContainer.visible = false;
|
||||
if (passphraseIsSetup) {
|
||||
if (isAuthenticated) {
|
||||
privateKeysReadyContainer.visible = true;
|
||||
} else {
|
||||
choosePassphraseContainer.visible = true;
|
||||
|
@ -117,7 +117,7 @@ Rectangle {
|
|||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 16;
|
||||
height: 280;
|
||||
|
||||
|
||||
Connections {
|
||||
onSendSignalToWallet: {
|
||||
sendSignalToWallet(msg);
|
||||
|
@ -210,7 +210,7 @@ Rectangle {
|
|||
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
commerce.getPassphraseSetupStatus();
|
||||
commerce.getWalletAuthenticatedStatus();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import QtQuick 2.5
|
||||
import QtGraphicalEffects 1.0
|
||||
import QtQuick.Layouts 1.3
|
||||
|
||||
import "../../styles-uit"
|
||||
import "../audio" as HifiAudio
|
||||
|
@ -109,15 +110,45 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
RalewaySemiBold {
|
||||
id: usernameText
|
||||
text: tabletRoot.username
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
Item {
|
||||
width: 150
|
||||
height: 50
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 20
|
||||
horizontalAlignment: Text.AlignRight
|
||||
font.pixelSize: 20
|
||||
color: "#afafaf"
|
||||
anchors.rightMargin: 30
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
RalewaySemiBold {
|
||||
text: Account.loggedIn ? qsTr("Log out") : qsTr("Log in")
|
||||
horizontalAlignment: Text.AlignRight
|
||||
anchors.right: parent.right
|
||||
font.pixelSize: 20
|
||||
color: "#afafaf"
|
||||
}
|
||||
|
||||
RalewaySemiBold {
|
||||
visible: Account.loggedIn
|
||||
height: Account.loggedIn ? parent.height/2 - parent.spacing/2 : 0
|
||||
text: Account.loggedIn ? "[" + tabletRoot.usernameShort + "]" : ""
|
||||
horizontalAlignment: Text.AlignRight
|
||||
anchors.right: parent.right
|
||||
font.pixelSize: 20
|
||||
color: "#afafaf"
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
if (!Account.loggedIn) {
|
||||
DialogsManager.showLoginDialog()
|
||||
} else {
|
||||
Account.logOut()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ Item {
|
|||
id: tabletRoot
|
||||
objectName: "tabletRoot"
|
||||
property string username: "Unknown user"
|
||||
property string usernameShort: "Unknown user"
|
||||
property var rootMenu;
|
||||
property var openModal: null;
|
||||
property var openMessage: null;
|
||||
|
@ -157,6 +158,11 @@ Item {
|
|||
|
||||
function setUsername(newUsername) {
|
||||
username = newUsername;
|
||||
usernameShort = newUsername.substring(0, 8);
|
||||
|
||||
if (newUsername.length > 8) {
|
||||
usernameShort = usernameShort + "..."
|
||||
}
|
||||
}
|
||||
|
||||
ListModel {
|
||||
|
|
|
@ -6337,11 +6337,11 @@ bool Application::askToWearAvatarAttachmentUrl(const QString& url) {
|
|||
|
||||
bool Application::askToReplaceDomainContent(const QString& url) {
|
||||
QString methodDetails;
|
||||
const int MAX_CHARACTERS_PER_LINE = 90;
|
||||
if (DependencyManager::get<NodeList>()->getThisNodeCanReplaceContent()) {
|
||||
QUrl originURL { url };
|
||||
if (originURL.host().endsWith(MARKETPLACE_CDN_HOSTNAME)) {
|
||||
// Create a confirmation dialog when this call is made
|
||||
const int MAX_CHARACTERS_PER_LINE = 90;
|
||||
static const QString infoText = simpleWordWrap("Your domain's content will be replaced with a new content set. "
|
||||
"If you want to save what you have now, create a backup before proceeding. For more information about backing up "
|
||||
"and restoring content, visit the documentation page at: ", MAX_CHARACTERS_PER_LINE) +
|
||||
|
@ -6377,7 +6377,9 @@ bool Application::askToReplaceDomainContent(const QString& url) {
|
|||
}
|
||||
} else {
|
||||
methodDetails = "UserDoesNotHavePermissionToReplaceContent";
|
||||
OffscreenUi::warning("Unable to replace content", "You do not have permissions to replace domain content",
|
||||
static const QString warningMessage = simpleWordWrap("The domain owner must enable 'Replace Content' "
|
||||
"permissions for you in this domain's server settings before you can continue.", MAX_CHARACTERS_PER_LINE);
|
||||
OffscreenUi::warning("You do not have permissions to replace domain content", warningMessage,
|
||||
QMessageBox::Ok, QMessageBox::Ok);
|
||||
}
|
||||
QJsonObject messageProperties = {
|
||||
|
|
|
@ -1889,6 +1889,17 @@ void MyAvatar::preDisplaySide(RenderArgs* renderArgs) {
|
|||
const bool shouldDrawHead = shouldRenderHead(renderArgs);
|
||||
if (shouldDrawHead != _prevShouldDrawHead) {
|
||||
_skeletonModel->setEnableCauterization(!shouldDrawHead);
|
||||
|
||||
for (int i = 0; i < _attachmentData.size(); i++) {
|
||||
if (_attachmentData[i].jointName.compare("Head", Qt::CaseInsensitive) == 0 ||
|
||||
_attachmentData[i].jointName.compare("Neck", Qt::CaseInsensitive) == 0 ||
|
||||
_attachmentData[i].jointName.compare("LeftEye", Qt::CaseInsensitive) == 0 ||
|
||||
_attachmentData[i].jointName.compare("RightEye", Qt::CaseInsensitive) == 0 ||
|
||||
_attachmentData[i].jointName.compare("HeadTop_End", Qt::CaseInsensitive) == 0 ||
|
||||
_attachmentData[i].jointName.compare("Face", Qt::CaseInsensitive) == 0) {
|
||||
_attachmentModels[i]->setVisibleInScene(shouldDrawHead, qApp->getMain3DScene());
|
||||
}
|
||||
}
|
||||
}
|
||||
_prevShouldDrawHead = shouldDrawHead;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QTimeZone>
|
||||
#include <QJsonDocument>
|
||||
#include "AccountManager.h"
|
||||
#include "Wallet.h"
|
||||
|
@ -45,7 +46,6 @@ Handler(buy)
|
|||
Handler(receiveAt)
|
||||
Handler(balance)
|
||||
Handler(inventory)
|
||||
Handler(history)
|
||||
|
||||
void Ledger::send(const QString& endpoint, const QString& success, const QString& fail, QNetworkAccessManager::Operation method, QJsonObject request) {
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
|
@ -108,6 +108,64 @@ void Ledger::inventory(const QStringList& keys) {
|
|||
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) {
|
||||
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::reset() {
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
auto ledger = DependencyManager::get<Ledger>();
|
||||
auto wallet = DependencyManager::get<Wallet>();
|
||||
|
@ -60,30 +84,14 @@ void QmlCommerce::history() {
|
|||
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) {
|
||||
emit passphraseSetupStatusResult(true);
|
||||
}
|
||||
|
||||
void QmlCommerce::getPassphraseSetupStatus() {
|
||||
emit passphraseSetupStatusResult(false);
|
||||
}
|
||||
void QmlCommerce::getKeyFilePathIfExists() {
|
||||
auto wallet = DependencyManager::get<Wallet>();
|
||||
wallet->sendKeyFilePathIfExists();
|
||||
if (wallet->getPassphrase() && !wallet->getPassphrase()->isEmpty()) {
|
||||
wallet->changePassphrase(passphrase);
|
||||
} else {
|
||||
wallet->setPassphrase(passphrase);
|
||||
}
|
||||
getWalletAuthenticatedStatus();
|
||||
}
|
||||
|
||||
void QmlCommerce::reset() {
|
||||
|
@ -91,4 +99,4 @@ void QmlCommerce::reset() {
|
|||
auto wallet = DependencyManager::get<Wallet>();
|
||||
ledger->reset();
|
||||
wallet->reset();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,28 +28,32 @@ public:
|
|||
QmlCommerce(QQuickItem* parent = nullptr);
|
||||
|
||||
signals:
|
||||
void loginStatusResult(bool isLoggedIn);
|
||||
void keyFilePathIfExistsResult(const QString& path);
|
||||
void securityImageResult(bool exists);
|
||||
void walletAuthenticatedStatusResult(bool isAuthenticated);
|
||||
|
||||
void buyResult(QJsonObject result);
|
||||
// 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).
|
||||
void balanceResult(QJsonObject result);
|
||||
void inventoryResult(QJsonObject result);
|
||||
void securityImageResult(bool exists);
|
||||
void loginStatusResult(bool isLoggedIn);
|
||||
void passphraseSetupStatusResult(bool passphraseIsSetup);
|
||||
void historyResult(QJsonObject result);
|
||||
void keyFilePathIfExistsResult(const QString& path);
|
||||
|
||||
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 balance();
|
||||
Q_INVOKABLE void inventory();
|
||||
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();
|
||||
};
|
||||
|
||||
|
|
|
@ -56,16 +56,72 @@ QString imageFilePath() {
|
|||
int passwordCallback(char* password, int maxPasswordSize, int rwFlag, void* u) {
|
||||
// just return a hardcoded pwd for now
|
||||
auto passphrase = DependencyManager::get<Wallet>()->getPassphrase();
|
||||
if (passphrase) {
|
||||
if (passphrase && !passphrase->isEmpty()) {
|
||||
strcpy(password, passphrase->toLocal8Bit().constData());
|
||||
return static_cast<int>(passphrase->size());
|
||||
} else {
|
||||
// ok gotta bring up modal dialog... But right now lets just
|
||||
// just keep it empty
|
||||
// this shouldn't happen - so lets log it to tell us we have
|
||||
// a problem with the flow...
|
||||
qCCritical(commerce) << "no cached passphrase while decrypting!";
|
||||
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
|
||||
// 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
|
||||
|
@ -124,25 +180,9 @@ QPair<QByteArray*, QByteArray*> generateRSAKeypair() {
|
|||
}
|
||||
|
||||
|
||||
|
||||
// now lets persist them to files
|
||||
// FIXME: for now I'm appending to the file if it exists. As long as we always put
|
||||
// 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);
|
||||
if (!writeKeys(keyFilePath().toStdString().c_str(), keyPair)) {
|
||||
qCDebug(commerce) << "couldn't save keys!";
|
||||
return retval;
|
||||
}
|
||||
|
||||
RSA_free(keyPair);
|
||||
|
@ -201,9 +241,6 @@ RSA* readPrivateKey(const char* filename) {
|
|||
// file opened successfully
|
||||
qCDebug(commerce) << "opened key file" << filename;
|
||||
if ((key = PEM_read_RSAPrivateKey(fp, &key, passwordCallback, NULL))) {
|
||||
// cleanup
|
||||
fclose(fp);
|
||||
|
||||
qCDebug(commerce) << "parsed private key file successfully";
|
||||
|
||||
} else {
|
||||
|
@ -215,7 +252,6 @@ RSA* readPrivateKey(const char* filename) {
|
|||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
static const unsigned char IVEC[16] = "IAmAnIVecYay123";
|
||||
|
||||
void initializeAESKeys(unsigned char* ivec, unsigned char* ckey, const QByteArray& salt) {
|
||||
|
@ -236,6 +272,10 @@ void Wallet::setPassphrase(const QString& passphrase) {
|
|||
delete _passphrase;
|
||||
}
|
||||
_passphrase = new QString(passphrase);
|
||||
|
||||
// no matter what, we now need to clear the keys as they
|
||||
// need to be read using this passphrase
|
||||
_publicKeys.clear();
|
||||
}
|
||||
|
||||
// encrypt some stuff
|
||||
|
@ -341,6 +381,38 @@ bool Wallet::decryptFile(const QString& inputFilePath, unsigned char** outputBuf
|
|||
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() {
|
||||
if (_publicKeys.count() > 0) return false;
|
||||
|
||||
|
@ -512,3 +584,30 @@ void Wallet::reset() {
|
|||
keyFile.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);
|
||||
QString* getPassphrase() { return _passphrase; }
|
||||
bool getPassphraseIsCached() { return !(_passphrase->isEmpty()); }
|
||||
bool walletIsAuthenticatedWithPassphrase();
|
||||
bool changePassphrase(const QString& newPassphrase);
|
||||
|
||||
void reset();
|
||||
|
||||
signals:
|
||||
void securityImageResult(bool exists) ;
|
||||
void securityImageResult(bool exists);
|
||||
void keyFilePathIfExistsResult(const QString& path);
|
||||
|
||||
private:
|
||||
QStringList _publicKeys{};
|
||||
QPixmap* _securityImage { nullptr };
|
||||
QByteArray _salt {"iamsalt!"};
|
||||
QString* _passphrase { new QString("pwd") };
|
||||
QString* _passphrase { new QString("") };
|
||||
|
||||
void updateImageProvider();
|
||||
bool encryptFile(const QString& inputFilePath, const QString& outputFilePath);
|
||||
|
|
|
@ -18,6 +18,8 @@ AccountScriptingInterface* AccountScriptingInterface::getInstance() {
|
|||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
QObject::connect(accountManager.data(), &AccountManager::profileChanged,
|
||||
&sharedInstance, &AccountScriptingInterface::usernameChanged);
|
||||
QObject::connect(accountManager.data(), &AccountManager::usernameChanged,
|
||||
&sharedInstance, &AccountScriptingInterface::onUsernameChanged);
|
||||
return &sharedInstance;
|
||||
}
|
||||
|
||||
|
@ -31,6 +33,21 @@ bool AccountScriptingInterface::checkAndSignalForAccessToken() {
|
|||
return accountManager->checkAndSignalForAccessToken();
|
||||
}
|
||||
|
||||
void AccountScriptingInterface::logOut() {
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
return accountManager->logout();
|
||||
}
|
||||
|
||||
AccountScriptingInterface::AccountScriptingInterface(QObject *parent): QObject(parent) {
|
||||
m_loggedIn = isLoggedIn();
|
||||
emit loggedInChanged(m_loggedIn);
|
||||
}
|
||||
|
||||
void AccountScriptingInterface::onUsernameChanged(QString username) {
|
||||
m_loggedIn = (username != QString());
|
||||
emit loggedInChanged(m_loggedIn);
|
||||
}
|
||||
|
||||
QString AccountScriptingInterface::getUsername() {
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
if (accountManager->isLoggedIn()) {
|
||||
|
|
|
@ -18,6 +18,7 @@ class AccountScriptingInterface : public QObject {
|
|||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString username READ getUsername NOTIFY usernameChanged)
|
||||
Q_PROPERTY(bool loggedIn READ loggedIn NOTIFY loggedInChanged)
|
||||
|
||||
/**jsdoc
|
||||
* @namespace Account
|
||||
|
@ -32,6 +33,7 @@ signals:
|
|||
* @return {Signal}
|
||||
*/
|
||||
void usernameChanged();
|
||||
void loggedInChanged(bool loggedIn);
|
||||
|
||||
public slots:
|
||||
static AccountScriptingInterface* getInstance();
|
||||
|
@ -50,6 +52,20 @@ public slots:
|
|||
*/
|
||||
bool isLoggedIn();
|
||||
bool checkAndSignalForAccessToken();
|
||||
void logOut();
|
||||
|
||||
public:
|
||||
AccountScriptingInterface(QObject* parent = nullptr);
|
||||
bool loggedIn() const {
|
||||
return m_loggedIn;
|
||||
}
|
||||
|
||||
private slots:
|
||||
void onUsernameChanged(QString username);
|
||||
|
||||
private:
|
||||
bool m_loggedIn { false };
|
||||
|
||||
};
|
||||
|
||||
#endif // hifi_AccountScriptingInterface_h
|
||||
|
|
|
@ -33,7 +33,12 @@ void DialogsManagerScriptingInterface::showAddressBar() {
|
|||
|
||||
void DialogsManagerScriptingInterface::hideAddressBar() {
|
||||
QMetaObject::invokeMethod(DependencyManager::get<DialogsManager>().data(),
|
||||
"hideAddressBar", Qt::QueuedConnection);
|
||||
"hideAddressBar", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void DialogsManagerScriptingInterface::showLoginDialog() {
|
||||
QMetaObject::invokeMethod(DependencyManager::get<DialogsManager>().data(),
|
||||
"showLoginDialog", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void DialogsManagerScriptingInterface::showFeed() {
|
||||
|
|
|
@ -24,6 +24,7 @@ public:
|
|||
public slots:
|
||||
void showAddressBar();
|
||||
void hideAddressBar();
|
||||
void showLoginDialog();
|
||||
|
||||
signals:
|
||||
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
|
||||
auto& fbxJoints = _animation->getGeometry().joints;
|
||||
auto& originalFbxJoints = _model->getFBXGeometry().joints;
|
||||
bool allowTranslation = entity->getAnimationAllowTranslation();
|
||||
int frameCount = frames.size();
|
||||
if (frameCount <= 0) {
|
||||
return;
|
||||
|
@ -952,7 +954,9 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
|
|||
int index = _jointMapping[j];
|
||||
if (index >= 0) {
|
||||
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]);
|
||||
}
|
||||
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 {
|
||||
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_FRAME_INDEX, Animation, animation, CurrentFrame, currentFrame);
|
||||
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) {
|
||||
|
||||
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, url, QString, setURL);
|
||||
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, allowTranslation, bool, setAllowTranslation);
|
||||
|
||||
// legacy property support
|
||||
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) {
|
||||
COPY_PROPERTY_IF_CHANGED(url);
|
||||
COPY_PROPERTY_IF_CHANGED(allowTranslation);
|
||||
COPY_PROPERTY_IF_CHANGED(fps);
|
||||
COPY_PROPERTY_IF_CHANGED(currentFrame);
|
||||
COPY_PROPERTY_IF_CHANGED(running);
|
||||
|
@ -88,6 +91,7 @@ void AnimationPropertyGroup::setFromOldAnimationSettings(const QString& value) {
|
|||
float lastFrame = getLastFrame();
|
||||
bool loop = getLoop();
|
||||
bool hold = getHold();
|
||||
bool allowTranslation = getAllowTranslation();
|
||||
|
||||
QJsonDocument settingsAsJson = QJsonDocument::fromJson(value.toUtf8());
|
||||
QJsonObject settingsAsJsonObject = settingsAsJson.object();
|
||||
|
@ -122,6 +126,11 @@ void AnimationPropertyGroup::setFromOldAnimationSettings(const QString& value) {
|
|||
running = settingsMap["hold"].toBool();
|
||||
}
|
||||
|
||||
if (settingsMap.contains("allowTranslation")) {
|
||||
allowTranslation = settingsMap["allowTranslation"].toBool();
|
||||
}
|
||||
|
||||
setAllowTranslation(allowTranslation);
|
||||
setFPS(fps);
|
||||
setCurrentFrame(currentFrame);
|
||||
setRunning(running);
|
||||
|
@ -137,6 +146,7 @@ void AnimationPropertyGroup::debugDump() const {
|
|||
qCDebug(entities) << " url:" << getURL() << " has changed:" << urlChanged();
|
||||
qCDebug(entities) << " fps:" << getFPS() << " has changed:" << fpsChanged();
|
||||
qCDebug(entities) << "currentFrame:" << getCurrentFrame() << " has changed:" << currentFrameChanged();
|
||||
qCDebug(entities) << "allowTranslation:" << getAllowTranslation() << " has changed:" << allowTranslationChanged();
|
||||
}
|
||||
|
||||
void AnimationPropertyGroup::listChangedProperties(QList<QString>& out) {
|
||||
|
@ -149,6 +159,9 @@ void AnimationPropertyGroup::listChangedProperties(QList<QString>& out) {
|
|||
if (currentFrameChanged()) {
|
||||
out << "animation-currentFrame";
|
||||
}
|
||||
if (allowTranslationChanged()) {
|
||||
out << "animation-allowTranslation";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -162,6 +175,7 @@ bool AnimationPropertyGroup::appendToEditPacket(OctreePacketData* packetData,
|
|||
bool successPropertyFits = true;
|
||||
|
||||
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_FRAME_INDEX, getCurrentFrame());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, getRunning());
|
||||
|
@ -181,6 +195,7 @@ bool AnimationPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyF
|
|||
bool somethingChanged = false;
|
||||
|
||||
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_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_LAST_FRAME, LastFrame);
|
||||
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_HOLD, Hold);
|
||||
|
||||
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_ALLOW_TRANSLATION, AllowTranslation);
|
||||
|
||||
processedBytes += bytesRead;
|
||||
|
||||
Q_UNUSED(somethingChanged);
|
||||
|
@ -215,6 +231,7 @@ void AnimationPropertyGroup::markAllChanged() {
|
|||
_firstFrameChanged = true;
|
||||
_lastFrameChanged = true;
|
||||
_holdChanged = true;
|
||||
_allowTranslationChanged = true;
|
||||
}
|
||||
|
||||
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_LAST_FRAME, lastFrame);
|
||||
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_HOLD, hold);
|
||||
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_ALLOW_TRANSLATION, allowTranslation);
|
||||
|
||||
return changedProperties;
|
||||
}
|
||||
|
||||
void AnimationPropertyGroup::getProperties(EntityItemProperties& properties) const {
|
||||
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, CurrentFrame, getCurrentFrame);
|
||||
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, Running, getRunning);
|
||||
|
@ -247,6 +266,7 @@ bool AnimationPropertyGroup::setProperties(const EntityItemProperties& propertie
|
|||
bool somethingChanged = false;
|
||||
|
||||
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, CurrentFrame, currentFrame, setCurrentFrame);
|
||||
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_LAST_FRAME;
|
||||
requestedProperties += PROP_ANIMATION_HOLD;
|
||||
requestedProperties += PROP_ANIMATION_ALLOW_TRANSLATION;
|
||||
|
||||
return requestedProperties;
|
||||
}
|
||||
|
@ -283,6 +304,7 @@ void AnimationPropertyGroup::appendSubclassData(OctreePacketData* packetData, En
|
|||
bool successPropertyFits = true;
|
||||
|
||||
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_FRAME_INDEX, getCurrentFrame());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, getRunning());
|
||||
|
@ -301,6 +323,7 @@ int AnimationPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char
|
|||
const unsigned char* dataAt = data;
|
||||
|
||||
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_FRAME_INDEX, float, setCurrentFrame);
|
||||
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_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_ALLOW_TRANSLATION, AllowTranslation, allowTranslation, bool, true);
|
||||
|
||||
protected:
|
||||
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_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_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_URL, Skybox, skybox, URL, url);
|
||||
|
|
|
@ -40,6 +40,7 @@ enum EntityPropertyList {
|
|||
PROP_ANIMATION_FPS,
|
||||
PROP_ANIMATION_FRAME_INDEX,
|
||||
PROP_ANIMATION_PLAYING,
|
||||
PROP_ANIMATION_ALLOW_TRANSLATION,
|
||||
|
||||
// these properties are supported by the EntityItem base class
|
||||
PROP_REGISTRATION_POINT,
|
||||
|
|
|
@ -330,6 +330,10 @@ void ModelEntityItem::setAnimationSettings(const QString& value) {
|
|||
setAnimationHold(hold);
|
||||
}
|
||||
|
||||
if (settingsMap.contains("allowTranslation")) {
|
||||
bool allowTranslation = settingsMap["allowTranslation"].toBool();
|
||||
setAnimationAllowTranslation(allowTranslation);
|
||||
}
|
||||
_dirtyFlags |= Simulation::DIRTY_UPDATEABLE;
|
||||
}
|
||||
|
||||
|
|
|
@ -83,7 +83,10 @@ public:
|
|||
|
||||
void setAnimationCurrentFrame(float 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);
|
||||
bool getAnimationLoop() const;
|
||||
|
|
|
@ -30,7 +30,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
|||
case PacketType::EntityEdit:
|
||||
case PacketType::EntityData:
|
||||
case PacketType::EntityPhysics:
|
||||
return VERSION_ENTITIES_HAS_HIGHLIGHT_SCRIPTING_INTERFACE;
|
||||
return VERSION_ENTITIES_ANIMATION_ALLOW_TRANSLATION_PROPERTIES;
|
||||
case PacketType::EntityQuery:
|
||||
return static_cast<PacketVersion>(EntityQueryPacketVersion::JSONFilterWithFamilyTree);
|
||||
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_HAS_SHOULD_HIGHLIGHT = 71;
|
||||
const PacketVersion VERSION_ENTITIES_HAS_HIGHLIGHT_SCRIPTING_INTERFACE = 72;
|
||||
const PacketVersion VERSION_ENTITIES_ANIMATION_ALLOW_TRANSLATION_PROPERTIES = 73;
|
||||
|
||||
enum class EntityQueryPacketVersion: PacketVersion {
|
||||
JSONFilter = 18,
|
||||
|
|
|
@ -92,6 +92,7 @@ void EntityMotionState::updateServerPhysicsVariables() {
|
|||
|
||||
Transform localTransform;
|
||||
_entity->getLocalTransformAndVelocities(localTransform, _serverVelocity, _serverAngularVelocity);
|
||||
_serverVariablesSet = true;
|
||||
_serverPosition = localTransform.getTranslation();
|
||||
_serverRotation = localTransform.getRotation();
|
||||
_serverAcceleration = _entity->getAcceleration();
|
||||
|
@ -99,18 +100,19 @@ void EntityMotionState::updateServerPhysicsVariables() {
|
|||
}
|
||||
|
||||
void EntityMotionState::handleDeactivation() {
|
||||
// copy _server data to entity
|
||||
bool success;
|
||||
_entity->setPosition(_serverPosition, success, false);
|
||||
_entity->setOrientation(_serverRotation, success, false);
|
||||
_entity->setVelocity(ENTITY_ITEM_ZERO_VEC3);
|
||||
_entity->setAngularVelocity(ENTITY_ITEM_ZERO_VEC3);
|
||||
// and also to RigidBody
|
||||
btTransform worldTrans;
|
||||
worldTrans.setOrigin(glmToBullet(_serverPosition));
|
||||
worldTrans.setRotation(glmToBullet(_serverRotation));
|
||||
_body->setWorldTransform(worldTrans);
|
||||
// no need to update velocities... should already be zero
|
||||
if (_serverVariablesSet) {
|
||||
// copy _server data to entity
|
||||
Transform localTransform = _entity->getLocalTransform();
|
||||
localTransform.setTranslation(_serverPosition);
|
||||
localTransform.setRotation(_serverRotation);
|
||||
_entity->setLocalTransformAndVelocities(localTransform, ENTITY_ITEM_ZERO_VEC3, ENTITY_ITEM_ZERO_VEC3);
|
||||
// and also to RigidBody
|
||||
btTransform worldTrans;
|
||||
worldTrans.setOrigin(glmToBullet(_entity->getPosition()));
|
||||
worldTrans.setRotation(glmToBullet(_entity->getRotation()));
|
||||
_body->setWorldTransform(worldTrans);
|
||||
// no need to update velocities... should already be zero
|
||||
}
|
||||
}
|
||||
|
||||
// virtual
|
||||
|
@ -339,6 +341,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
|
|||
// if we've never checked before, our _lastStep will be 0, and we need to initialize our state
|
||||
if (_lastStep == 0) {
|
||||
btTransform xform = _body->getWorldTransform();
|
||||
_serverVariablesSet = true;
|
||||
_serverPosition = worldToLocal.transform(bulletToGLM(xform.getOrigin()));
|
||||
_serverRotation = worldToLocal.getRotation() * bulletToGLM(xform.getRotation());
|
||||
_serverVelocity = worldVelocityToLocal.transform(getBodyLinearVelocityGTSigma());
|
||||
|
|
|
@ -107,6 +107,7 @@ protected:
|
|||
// Meanwhile we also keep a raw EntityItem* for internal stuff where the pointer is guaranteed valid.
|
||||
EntityItem* _entity;
|
||||
|
||||
bool _serverVariablesSet { false };
|
||||
glm::vec3 _serverPosition; // in simulation-frame (not world-frame)
|
||||
glm::quat _serverRotation;
|
||||
glm::vec3 _serverVelocity;
|
||||
|
|
|
@ -827,10 +827,10 @@ AnimationDetails::AnimationDetails() :
|
|||
}
|
||||
|
||||
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),
|
||||
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("running", details.running);
|
||||
obj.setProperty("currentFrame", details.currentFrame);
|
||||
obj.setProperty("allowTranslation", details.allowTranslation);
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
|
|
@ -197,7 +197,7 @@ class AnimationDetails {
|
|||
public:
|
||||
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);
|
||||
|
||||
QString role;
|
||||
QUrl url;
|
||||
|
@ -210,6 +210,7 @@ public:
|
|||
float lastFrame;
|
||||
bool running;
|
||||
float currentFrame;
|
||||
bool allowTranslation;
|
||||
};
|
||||
Q_DECLARE_METATYPE(AnimationDetails);
|
||||
QScriptValue animationDetailsToScriptValue(QScriptEngine* engine, const AnimationDetails& event);
|
||||
|
|
|
@ -706,7 +706,7 @@ void SpatiallyNestable::setSNScale(const glm::vec3& scale, bool& success) {
|
|||
}
|
||||
}
|
||||
|
||||
const Transform SpatiallyNestable::getLocalTransform() const {
|
||||
Transform SpatiallyNestable::getLocalTransform() const {
|
||||
Transform result;
|
||||
_transformLock.withReadLock([&] {
|
||||
result =_transform;
|
||||
|
|
|
@ -122,7 +122,7 @@ public:
|
|||
virtual glm::vec3 getSNScale(int jointIndex, bool& success) const;
|
||||
|
||||
// object's parent's frame
|
||||
virtual const Transform getLocalTransform() const;
|
||||
virtual Transform getLocalTransform() const;
|
||||
virtual void setLocalTransform(const Transform& transform);
|
||||
|
||||
virtual glm::vec3 getLocalPosition() const;
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
var isHmdPreviewDisabled = true;
|
||||
function fromQml(message) {
|
||||
switch (message.method) {
|
||||
case 'passphrasePopup_cancelClicked':
|
||||
case 'walletSetup_cancelClicked':
|
||||
case 'needsLogIn_cancelClicked':
|
||||
tablet.gotoHomeScreen();
|
||||
|
|
|
@ -446,6 +446,10 @@
|
|||
<input type="checkbox" id="property-model-animation-hold">
|
||||
<label for="property-model-animation-hold">Animation hold</label>
|
||||
</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">
|
||||
<label>Animation FPS</label>
|
||||
<input type="number" id="property-model-animation-fps">
|
||||
|
@ -642,10 +646,6 @@
|
|||
</div>
|
||||
</fieldset>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<fieldset id="polyvox" class="major">
|
||||
<legend class="section-header spatial-group poly-vox-section property xyz">
|
||||
Voxel volume size <span>m</span>
|
||||
|
|
|
@ -611,6 +611,7 @@ function loaded() {
|
|||
var elModelAnimationLastFrame = document.getElementById("property-model-animation-last-frame");
|
||||
var elModelAnimationLoop = document.getElementById("property-model-animation-loop");
|
||||
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 elModelOriginalTextures = document.getElementById("property-model-original-textures");
|
||||
|
||||
|
@ -926,6 +927,7 @@ function loaded() {
|
|||
elModelAnimationLastFrame.value = properties.animation.lastFrame;
|
||||
elModelAnimationLoop.checked = properties.animation.loop;
|
||||
elModelAnimationHold.checked = properties.animation.hold;
|
||||
elModelAnimationAllowTranslation.checked = properties.animation.allowTranslation;
|
||||
elModelTextures.value = properties.textures;
|
||||
setTextareaScrolling(elModelTextures);
|
||||
elModelOriginalTextures.value = properties.originalTextures;
|
||||
|
@ -1276,6 +1278,7 @@ function loaded() {
|
|||
elModelAnimationLastFrame.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('animation', 'lastFrame'));
|
||||
elModelAnimationLoop.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('animation', 'loop'));
|
||||
elModelAnimationHold.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('animation', 'hold'));
|
||||
elModelAnimationAllowTranslation.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('animation', 'allowTranslation'));
|
||||
|
||||
elModelTextures.addEventListener('change', createEmitTextPropertyUpdateFunction('textures'));
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
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
|
||||
|
||||
|
||||
function injectCommonCode(isDirectoryPage) {
|
||||
|
||||
// Supporting styles from marketplaces.css.
|
||||
|
@ -122,7 +122,7 @@
|
|||
|
||||
function injectBuyButtonOnMainPage() {
|
||||
var cost;
|
||||
|
||||
|
||||
$('.grid-item').find('#price-or-edit').find('a').each(function() {
|
||||
$(this).attr('data-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').attr("class", 'col-xs-6');
|
||||
|
||||
|
||||
if (parseInt(cost) > 0) {
|
||||
var priceElement = $(this).find('.price')
|
||||
priceElement.css({ "width": "auto", "padding": "3px 5px", "height": "26px" });
|
||||
priceElement.text(parseFloat(cost / 100).toFixed(2) + ' HFC');
|
||||
priceElement.text(cost + ' HFC');
|
||||
priceElement.css({ "min-width": priceElement.width() + 10 });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
$('.grid-item').find('#price-or-edit').find('a').on('click', function () {
|
||||
buyButtonClicked($(this).closest('.grid-item').attr('data-item-id'),
|
||||
$(this).closest('.grid-item').find('.item-title').text(),
|
||||
|
@ -175,11 +175,12 @@
|
|||
if (confirmAllPurchases) {
|
||||
var href = $('#side-info').find('.btn').first().attr('href');
|
||||
$('#side-info').find('.btn').first().attr('href', '#');
|
||||
|
||||
|
||||
var cost = $('.item-cost').text();
|
||||
|
||||
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 () {
|
||||
|
@ -264,7 +265,7 @@
|
|||
// 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";
|
||||
// 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.
|
||||
var XMLHTTPREQUEST_URL = "https://clara.io/api/scenes/{uuid}/export/fbx?fbxUnit=Meter&fbxVersion=5&fbxEmbedTextures=true&imageFormat=WebGL";
|
||||
|
||||
|
@ -447,7 +448,7 @@
|
|||
cancelClaraDownload();
|
||||
} else {
|
||||
var parsedJsonMessage = JSON.parse(message);
|
||||
|
||||
|
||||
if (parsedJsonMessage.type === "marketplaces") {
|
||||
if (parsedJsonMessage.action === "inspectionModeSetting") {
|
||||
confirmAllPurchases = !!parsedJsonMessage.data;
|
||||
|
|
|
@ -197,6 +197,7 @@
|
|||
// Description:
|
||||
// -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.
|
||||
var isHmdPreviewDisabled = true;
|
||||
function fromQml(message) {
|
||||
switch (message.method) {
|
||||
case 'checkout_setUpClicked':
|
||||
|
@ -231,12 +232,20 @@
|
|||
case 'purchases_goToMarketplaceClicked':
|
||||
tablet.gotoWebScreen(MARKETPLACE_URL_INITIAL, MARKETPLACES_INJECT_SCRIPT_URL);
|
||||
break;
|
||||
case 'passphrasePopup_cancelClicked':
|
||||
case 'needsLogIn_cancelClicked':
|
||||
tablet.gotoWebScreen(MARKETPLACE_URL_INITIAL, MARKETPLACES_INJECT_SCRIPT_URL);
|
||||
break;
|
||||
case 'needsLogIn_loginClicked':
|
||||
openLoginWindow();
|
||||
break;
|
||||
case 'disableHmdPreview':
|
||||
isHmdPreviewDisabled = Menu.isOptionChecked("Disable Preview");
|
||||
Menu.setIsOptionChecked("Disable Preview", true);
|
||||
break;
|
||||
case 'maybeEnableHmdPreview':
|
||||
Menu.setIsOptionChecked("Disable Preview", isHmdPreviewDisabled);
|
||||
break;
|
||||
default:
|
||||
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