Merge branch 'master' of git://github.com/highfidelity/hifi into bloom
39
.clang-format
Normal file
|
@ -0,0 +1,39 @@
|
|||
Language: Cpp
|
||||
Standard: Cpp11
|
||||
BasedOnStyle: "Chromium"
|
||||
ColumnLimit: 128
|
||||
IndentWidth: 4
|
||||
UseTab: Never
|
||||
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterEnum: true
|
||||
AfterClass: false
|
||||
AfterControlStatement: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyNamespace: true
|
||||
|
||||
|
||||
AccessModifierOffset: -4
|
||||
AllowShortFunctionsOnASingleLine: InlineOnly
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakConstructorInitializersBeforeComma: true
|
||||
IndentCaseLabels: true
|
||||
ReflowComments: false
|
||||
Cpp11BracedListStyle: false
|
||||
ContinuationIndentWidth: 4
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
CompactNamespaces: true
|
||||
SortIncludes: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
|
||||
PenaltyReturnTypeOnItsOwnLine: 1000
|
||||
PenaltyBreakBeforeFirstCallParameter: 1000
|
||||
|
9
.gitignore
vendored
|
@ -17,6 +17,15 @@ Makefile
|
|||
local.properties
|
||||
android/libraries
|
||||
|
||||
# VSCode
|
||||
# List taken from Github Global Ignores master@435c4d92
|
||||
# https://github.com/github/gitignore/commits/master/Global/VisualStudioCode.gitignore
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
|
||||
# Xcode
|
||||
*.xcodeproj
|
||||
*.xcworkspace
|
||||
|
|
2
BUILD.md
|
@ -25,7 +25,7 @@ The above dependencies will be downloaded, built, linked and included automatica
|
|||
|
||||
These are not placed in your normal build tree when doing an out of source build so that they do not need to be re-downloaded and re-compiled every time the CMake build folder is cleared. Should you want to force a re-download and re-compile of a specific external, you can simply remove that directory from the appropriate subfolder in `build/ext`. Should you want to force a re-download and re-compile of all externals, just remove the `build/ext` folder.
|
||||
|
||||
If you would like to use a specific install of a dependency instead of the version that would be grabbed as a CMake ExternalProject, you can pass -DUSE_LOCAL_$NAME=0 (where $NAME is the name of the subfolder in [cmake/externals](cmake/externals)) when you run CMake to tell it not to get that dependency as an external project.
|
||||
If you would like to use a specific install of a dependency instead of the version that would be grabbed as a CMake ExternalProject, you can pass -DUSE\_LOCAL\_$NAME=0 (where $NAME is the name of the subfolder in [cmake/externals](cmake/externals)) when you run CMake to tell it not to get that dependency as an external project.
|
||||
|
||||
### OS Specific Build Guides
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include <ClientServerUtils.h>
|
||||
#include <FBXBaker.h>
|
||||
#include <JSBaker.h>
|
||||
#include <NodeType.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <PathUtils.h>
|
||||
|
@ -51,8 +52,10 @@ const QString ASSET_SERVER_LOGGING_TARGET_NAME = "asset-server";
|
|||
|
||||
static const QStringList BAKEABLE_MODEL_EXTENSIONS = { "fbx" };
|
||||
static QStringList BAKEABLE_TEXTURE_EXTENSIONS;
|
||||
static const QStringList BAKEABLE_SCRIPT_EXTENSIONS = {};
|
||||
static const QString BAKED_MODEL_SIMPLE_NAME = "asset.fbx";
|
||||
static const QString BAKED_TEXTURE_SIMPLE_NAME = "texture.ktx";
|
||||
static const QString BAKED_SCRIPT_SIMPLE_NAME = "asset.js";
|
||||
|
||||
void AssetServer::bakeAsset(const AssetHash& assetHash, const AssetPath& assetPath, const QString& filePath) {
|
||||
qDebug() << "Starting bake for: " << assetPath << assetHash;
|
||||
|
@ -99,6 +102,8 @@ std::pair<BakingStatus, QString> AssetServer::getAssetStatus(const AssetPath& pa
|
|||
bakedFilename = BAKED_MODEL_SIMPLE_NAME;
|
||||
} else if (BAKEABLE_TEXTURE_EXTENSIONS.contains(extension.toLocal8Bit()) && hasMetaFile(hash)) {
|
||||
bakedFilename = BAKED_TEXTURE_SIMPLE_NAME;
|
||||
} else if (BAKEABLE_SCRIPT_EXTENSIONS.contains(extension)) {
|
||||
bakedFilename = BAKED_SCRIPT_SIMPLE_NAME;
|
||||
} else {
|
||||
return { Irrelevant, "" };
|
||||
}
|
||||
|
@ -186,6 +191,8 @@ bool AssetServer::needsToBeBaked(const AssetPath& path, const AssetHash& assetHa
|
|||
bakedFilename = BAKED_MODEL_SIMPLE_NAME;
|
||||
} else if (loaded && BAKEABLE_TEXTURE_EXTENSIONS.contains(extension.toLocal8Bit())) {
|
||||
bakedFilename = BAKED_TEXTURE_SIMPLE_NAME;
|
||||
} else if (BAKEABLE_SCRIPT_EXTENSIONS.contains(extension)) {
|
||||
bakedFilename = BAKED_SCRIPT_SIMPLE_NAME;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -228,7 +235,8 @@ void updateConsumedCores() {
|
|||
AssetServer::AssetServer(ReceivedMessage& message) :
|
||||
ThreadedAssignment(message),
|
||||
_transferTaskPool(this),
|
||||
_bakingTaskPool(this)
|
||||
_bakingTaskPool(this),
|
||||
_filesizeLimit(MAX_UPLOAD_SIZE)
|
||||
{
|
||||
// store the current state of image compression so we can reset it when this assignment is complete
|
||||
_wasColorTextureCompressionEnabled = image::isColorTexturesCompressionEnabled();
|
||||
|
@ -336,8 +344,8 @@ void AssetServer::completeSetup() {
|
|||
auto maxBandwidthValue = assetServerObject[MAX_BANDWIDTH_OPTION];
|
||||
auto maxBandwidthFloat = maxBandwidthValue.toDouble(-1);
|
||||
|
||||
const int BITS_PER_MEGABITS = 1000 * 1000;
|
||||
if (maxBandwidthFloat > 0.0) {
|
||||
const int BITS_PER_MEGABITS = 1000 * 1000;
|
||||
int maxBandwidth = maxBandwidthFloat * BITS_PER_MEGABITS;
|
||||
nodeList->setConnectionMaxBandwidth(maxBandwidth);
|
||||
qCInfo(asset_server) << "Set maximum bandwith per connection to" << maxBandwidthFloat << "Mb/s."
|
||||
|
@ -399,6 +407,15 @@ void AssetServer::completeSetup() {
|
|||
qCCritical(asset_server) << "Asset Server assignment will not continue because mapping file could not be loaded.";
|
||||
setFinished(true);
|
||||
}
|
||||
|
||||
// get file size limit for an asset
|
||||
static const QString ASSETS_FILESIZE_LIMIT_OPTION = "assets_filesize_limit";
|
||||
auto assetsFilesizeLimitJSONValue = assetServerObject[ASSETS_FILESIZE_LIMIT_OPTION];
|
||||
auto assetsFilesizeLimit = (uint64_t)assetsFilesizeLimitJSONValue.toInt(MAX_UPLOAD_SIZE);
|
||||
|
||||
if (assetsFilesizeLimit != 0 && assetsFilesizeLimit < MAX_UPLOAD_SIZE) {
|
||||
_filesizeLimit = assetsFilesizeLimit * BITS_PER_MEGABITS;
|
||||
}
|
||||
}
|
||||
|
||||
void AssetServer::cleanupUnmappedFiles() {
|
||||
|
@ -488,6 +505,8 @@ void AssetServer::handleGetMappingOperation(ReceivedMessage& message, SharedNode
|
|||
bakedRootFile = BAKED_MODEL_SIMPLE_NAME;
|
||||
} else if (BAKEABLE_TEXTURE_EXTENSIONS.contains(assetPathExtension.toLocal8Bit())) {
|
||||
bakedRootFile = BAKED_TEXTURE_SIMPLE_NAME;
|
||||
} else if (BAKEABLE_SCRIPT_EXTENSIONS.contains(assetPathExtension)) {
|
||||
bakedRootFile = BAKED_SCRIPT_SIMPLE_NAME;
|
||||
}
|
||||
|
||||
auto originalAssetHash = it->second;
|
||||
|
@ -721,7 +740,7 @@ void AssetServer::handleAssetUpload(QSharedPointer<ReceivedMessage> message, Sha
|
|||
if (senderNode->getCanWriteToAssetServer()) {
|
||||
qCDebug(asset_server) << "Starting an UploadAssetTask for upload from" << uuidStringWithoutCurlyBraces(senderNode->getUUID());
|
||||
|
||||
auto task = new UploadAssetTask(message, senderNode, _filesDirectory);
|
||||
auto task = new UploadAssetTask(message, senderNode, _filesDirectory, _filesizeLimit);
|
||||
_transferTaskPool.start(task);
|
||||
} else {
|
||||
// this is a node the domain told us is not allowed to rez entities
|
||||
|
@ -1141,6 +1160,7 @@ bool AssetServer::renameMapping(AssetPath oldPath, AssetPath newPath) {
|
|||
|
||||
static const QString BAKED_ASSET_SIMPLE_FBX_NAME = "asset.fbx";
|
||||
static const QString BAKED_ASSET_SIMPLE_TEXTURE_NAME = "texture.ktx";
|
||||
static const QString BAKED_ASSET_SIMPLE_JS_NAME = "asset.js";
|
||||
|
||||
QString getBakeMapping(const AssetHash& hash, const QString& relativeFilePath) {
|
||||
return HIDDEN_BAKED_CONTENT_FOLDER + hash + "/" + relativeFilePath;
|
||||
|
@ -1204,14 +1224,14 @@ void AssetServer::handleCompletedBake(QString originalAssetHash, QString origina
|
|||
// setup the mapping for this bake file
|
||||
auto relativeFilePath = QUrl(filePath).fileName();
|
||||
qDebug() << "Relative file path is: " << relativeFilePath;
|
||||
|
||||
if (relativeFilePath.endsWith(".fbx", Qt::CaseInsensitive)) {
|
||||
// for an FBX file, we replace the filename with the simple name
|
||||
// (to handle the case where two mapped assets have the same hash but different names)
|
||||
relativeFilePath = BAKED_ASSET_SIMPLE_FBX_NAME;
|
||||
} else if (relativeFilePath.endsWith(".js", Qt::CaseInsensitive)) {
|
||||
relativeFilePath = BAKED_ASSET_SIMPLE_JS_NAME;
|
||||
} else if (!originalAssetPath.endsWith(".fbx", Qt::CaseInsensitive)) {
|
||||
relativeFilePath = BAKED_ASSET_SIMPLE_TEXTURE_NAME;
|
||||
|
||||
}
|
||||
|
||||
QString bakeMapping = getBakeMapping(originalAssetHash, relativeFilePath);
|
||||
|
@ -1364,6 +1384,8 @@ bool AssetServer::setBakingEnabled(const AssetPathList& paths, bool enabled) {
|
|||
bakedFilename = BAKED_MODEL_SIMPLE_NAME;
|
||||
} else if (BAKEABLE_TEXTURE_EXTENSIONS.contains(extension.toLocal8Bit()) && hasMetaFile(hash)) {
|
||||
bakedFilename = BAKED_TEXTURE_SIMPLE_NAME;
|
||||
} else if (BAKEABLE_SCRIPT_EXTENSIONS.contains(extension)) {
|
||||
bakedFilename = BAKED_SCRIPT_SIMPLE_NAME;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -127,6 +127,8 @@ private:
|
|||
bool _wasGrayscaleTextureCompressionEnabled { false };
|
||||
bool _wasNormalTextureCompressionEnabled { false };
|
||||
bool _wasCubeTextureCompressionEnabled { false };
|
||||
|
||||
uint64_t _filesizeLimit;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include <FBXBaker.h>
|
||||
#include <PathUtils.h>
|
||||
#include <JSBaker.h>
|
||||
|
||||
BakeAssetTask::BakeAssetTask(const AssetHash& assetHash, const AssetPath& assetPath, const QString& filePath) :
|
||||
_assetHash(assetHash),
|
||||
|
@ -52,6 +53,10 @@ void BakeAssetTask::run() {
|
|||
_baker = std::unique_ptr<FBXBaker> {
|
||||
new FBXBaker(QUrl("file:///" + _filePath), fn, tempOutputDir)
|
||||
};
|
||||
} else if (_assetPath.endsWith(".js", Qt::CaseInsensitive)) {
|
||||
_baker = std::unique_ptr<JSBaker>{
|
||||
new JSBaker(QUrl("file:///" + _filePath), PathUtils::generateTemporaryDir())
|
||||
};
|
||||
} else {
|
||||
tempOutputDir = PathUtils::generateTemporaryDir();
|
||||
_baker = std::unique_ptr<TextureBaker> {
|
||||
|
|
|
@ -22,10 +22,11 @@
|
|||
|
||||
|
||||
UploadAssetTask::UploadAssetTask(QSharedPointer<ReceivedMessage> receivedMessage, SharedNodePointer senderNode,
|
||||
const QDir& resourcesDir) :
|
||||
const QDir& resourcesDir, uint64_t filesizeLimit) :
|
||||
_receivedMessage(receivedMessage),
|
||||
_senderNode(senderNode),
|
||||
_resourcesDir(resourcesDir)
|
||||
_resourcesDir(resourcesDir),
|
||||
_filesizeLimit(filesizeLimit)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -48,7 +49,7 @@ void UploadAssetTask::run() {
|
|||
auto replyPacket = NLPacket::create(PacketType::AssetUploadReply, -1, true);
|
||||
replyPacket->writePrimitive(messageID);
|
||||
|
||||
if (fileSize > MAX_UPLOAD_SIZE) {
|
||||
if (fileSize > _filesizeLimit) {
|
||||
replyPacket->writePrimitive(AssetServerError::AssetTooLarge);
|
||||
} else {
|
||||
QByteArray fileData = buffer.read(fileSize);
|
||||
|
|
|
@ -26,7 +26,8 @@ class Node;
|
|||
|
||||
class UploadAssetTask : public QRunnable {
|
||||
public:
|
||||
UploadAssetTask(QSharedPointer<ReceivedMessage> message, QSharedPointer<Node> senderNode, const QDir& resourcesDir);
|
||||
UploadAssetTask(QSharedPointer<ReceivedMessage> message, QSharedPointer<Node> senderNode,
|
||||
const QDir& resourcesDir, uint64_t filesizeLimit);
|
||||
|
||||
void run() override;
|
||||
|
||||
|
@ -34,6 +35,7 @@ private:
|
|||
QSharedPointer<ReceivedMessage> _receivedMessage;
|
||||
QSharedPointer<Node> _senderNode;
|
||||
QDir _resourcesDir;
|
||||
uint64_t _filesizeLimit;
|
||||
};
|
||||
|
||||
#endif // hifi_UploadAssetTask_h
|
||||
|
|
|
@ -97,7 +97,11 @@ void AudioMixerSlavePool::run(ConstIter begin, ConstIter end) {
|
|||
#else
|
||||
// fill the queue
|
||||
std::for_each(_begin, _end, [&](const SharedNodePointer& node) {
|
||||
#if defined(__clang__) && defined(Q_OS_LINUX)
|
||||
_queue.push(node);
|
||||
#else
|
||||
_queue.emplace(node);
|
||||
#endif
|
||||
});
|
||||
|
||||
{
|
||||
|
|
|
@ -97,7 +97,11 @@ void AvatarMixerSlavePool::run(ConstIter begin, ConstIter end) {
|
|||
#else
|
||||
// fill the queue
|
||||
std::for_each(_begin, _end, [&](const SharedNodePointer& node) {
|
||||
#if defined(__clang__) && defined(Q_OS_LINUX)
|
||||
_queue.push(node);
|
||||
#else
|
||||
_queue.emplace(node);
|
||||
#endif
|
||||
});
|
||||
|
||||
{
|
||||
|
|
|
@ -16,6 +16,10 @@
|
|||
#include <ResourceCache.h>
|
||||
#include <ScriptCache.h>
|
||||
#include <EntityEditFilters.h>
|
||||
#include <NetworkingConstants.h>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <AddressManager.h>
|
||||
|
||||
#include "AssignmentParentFinder.h"
|
||||
#include "EntityNodeData.h"
|
||||
|
@ -29,15 +33,26 @@ const char* LOCAL_MODELS_PERSIST_FILE = "resources/models.svo";
|
|||
|
||||
EntityServer::EntityServer(ReceivedMessage& message) :
|
||||
OctreeServer(message),
|
||||
_entitySimulation(NULL)
|
||||
_entitySimulation(NULL),
|
||||
_dynamicDomainVerificationTimer(this)
|
||||
{
|
||||
DependencyManager::set<ResourceManager>();
|
||||
DependencyManager::set<ResourceCacheSharedItems>();
|
||||
DependencyManager::set<ScriptCache>();
|
||||
|
||||
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
|
||||
packetReceiver.registerListenerForTypes({ PacketType::EntityAdd, PacketType::EntityEdit, PacketType::EntityErase, PacketType::EntityPhysics },
|
||||
this, "handleEntityPacket");
|
||||
packetReceiver.registerListenerForTypes({ PacketType::EntityAdd,
|
||||
PacketType::EntityEdit,
|
||||
PacketType::EntityErase,
|
||||
PacketType::EntityPhysics,
|
||||
PacketType::ChallengeOwnership,
|
||||
PacketType::ChallengeOwnershipRequest,
|
||||
PacketType::ChallengeOwnershipReply },
|
||||
this,
|
||||
"handleEntityPacket");
|
||||
|
||||
connect(&_dynamicDomainVerificationTimer, &QTimer::timeout, this, &EntityServer::startDynamicDomainVerification);
|
||||
_dynamicDomainVerificationTimer.setSingleShot(true);
|
||||
}
|
||||
|
||||
EntityServer::~EntityServer() {
|
||||
|
@ -93,6 +108,9 @@ void EntityServer::beforeRun() {
|
|||
connect(_pruneDeletedEntitiesTimer, SIGNAL(timeout()), this, SLOT(pruneDeletedEntities()));
|
||||
const int PRUNE_DELETED_MODELS_INTERVAL_MSECS = 1 * 1000; // once every second
|
||||
_pruneDeletedEntitiesTimer->start(PRUNE_DELETED_MODELS_INTERVAL_MSECS);
|
||||
|
||||
DomainHandler& domainHandler = DependencyManager::get<NodeList>()->getDomainHandler();
|
||||
connect(&domainHandler, &DomainHandler::settingsReceiveFail, this, &EntityServer::domainSettingsRequestFailed);
|
||||
}
|
||||
|
||||
void EntityServer::entityCreated(const EntityItem& newEntity, const SharedNodePointer& senderNode) {
|
||||
|
@ -296,6 +314,18 @@ void EntityServer::readAdditionalConfiguration(const QJsonObject& settingsSectio
|
|||
tree->setEntityMaxTmpLifetime(EntityTree::DEFAULT_MAX_TMP_ENTITY_LIFETIME);
|
||||
}
|
||||
|
||||
int minTime;
|
||||
if (readOptionInt("dynamicDomainVerificationTimeMin", settingsSectionObject, minTime)) {
|
||||
_MINIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS = minTime * 1000;
|
||||
}
|
||||
|
||||
int maxTime;
|
||||
if (readOptionInt("dynamicDomainVerificationTimeMax", settingsSectionObject, maxTime)) {
|
||||
_MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS = maxTime * 1000;
|
||||
}
|
||||
|
||||
startDynamicDomainVerification();
|
||||
|
||||
tree->setWantEditLogging(wantEditLogging);
|
||||
tree->setWantTerseEditLogging(wantTerseEditLogging);
|
||||
|
||||
|
@ -410,3 +440,79 @@ QString EntityServer::serverSubclassStats() {
|
|||
|
||||
return statsString;
|
||||
}
|
||||
|
||||
void EntityServer::domainSettingsRequestFailed() {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
qCDebug(entities) << "The EntityServer couldn't get the Domain Settings. Starting dynamic domain verification with default values...";
|
||||
|
||||
_MINIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS = DEFAULT_MINIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS;
|
||||
_MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS = DEFAULT_MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS;
|
||||
startDynamicDomainVerification();
|
||||
}
|
||||
|
||||
void EntityServer::startDynamicDomainVerification() {
|
||||
qCDebug(entities) << "Starting Dynamic Domain Verification...";
|
||||
|
||||
QString thisDomainID = DependencyManager::get<AddressManager>()->getDomainId().remove(QRegExp("\\{|\\}"));
|
||||
|
||||
EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_tree);
|
||||
QHash<QString, EntityItemID> localMap(tree->getEntityCertificateIDMap());
|
||||
|
||||
QHashIterator<QString, EntityItemID> i(localMap);
|
||||
qCDebug(entities) << localMap.size() << "entities in _entityCertificateIDMap";
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
|
||||
EntityItemPointer entity = tree->findEntityByEntityItemID(i.value());
|
||||
|
||||
if (entity) {
|
||||
if (!entity->getProperties().verifyStaticCertificateProperties()) {
|
||||
qCDebug(entities) << "During Dynamic Domain Verification, a certified entity with ID" << i.value() << "failed"
|
||||
<< "static certificate verification.";
|
||||
// Delete the entity if it doesn't pass static certificate verification
|
||||
tree->deleteEntity(i.value(), true);
|
||||
} else {
|
||||
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest networkRequest;
|
||||
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL;
|
||||
requestURL.setPath("/api/v1/commerce/proof_of_purchase_status/location");
|
||||
QJsonObject request;
|
||||
request["certificate_id"] = i.key();
|
||||
networkRequest.setUrl(requestURL);
|
||||
|
||||
QNetworkReply* networkReply = NULL;
|
||||
networkReply = networkAccessManager.put(networkRequest, QJsonDocument(request).toJson());
|
||||
|
||||
connect(networkReply, &QNetworkReply::finished, [=]() {
|
||||
QJsonObject jsonObject = QJsonDocument::fromJson(networkReply->readAll()).object();
|
||||
jsonObject = jsonObject["data"].toObject();
|
||||
|
||||
if (networkReply->error() == QNetworkReply::NoError) {
|
||||
if (jsonObject["domain_id"].toString() != thisDomainID) {
|
||||
qCDebug(entities) << "Entity's cert's domain ID" << jsonObject["domain_id"].toString()
|
||||
<< "doesn't match the current Domain ID" << thisDomainID << "; deleting entity" << i.value();
|
||||
tree->deleteEntity(i.value(), true);
|
||||
} else {
|
||||
qCDebug(entities) << "Entity passed dynamic domain verification:" << i.value();
|
||||
}
|
||||
} else {
|
||||
qCDebug(entities) << "Call to" << networkReply->url() << "failed with error" << networkReply->error() << "; deleting entity" << i.value()
|
||||
<< "More info:" << jsonObject;
|
||||
tree->deleteEntity(i.value(), true);
|
||||
}
|
||||
|
||||
networkReply->deleteLater();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
qCWarning(entities) << "During DDV, an entity with ID" << i.value() << "was NOT found in the Entity Tree!";
|
||||
}
|
||||
}
|
||||
|
||||
int nextInterval = qrand() % ((_MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS + 1) - _MINIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS) + _MINIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS;
|
||||
qCDebug(entities) << "Restarting Dynamic Domain Verification timer for" << nextInterval / 1000 << "seconds";
|
||||
_dynamicDomainVerificationTimer.start(nextInterval);
|
||||
}
|
||||
|
|
|
@ -73,6 +73,7 @@ protected:
|
|||
|
||||
private slots:
|
||||
void handleEntityPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
|
||||
void domainSettingsRequestFailed();
|
||||
|
||||
private:
|
||||
SimpleEntitySimulationPointer _entitySimulation;
|
||||
|
@ -80,6 +81,13 @@ private:
|
|||
|
||||
QReadWriteLock _viewerSendingStatsLock;
|
||||
QMap<QUuid, QMap<QUuid, ViewerSendingStats>> _viewerSendingStats;
|
||||
|
||||
static const int DEFAULT_MINIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS = 45 * 60 * 1000; // 45m
|
||||
static const int DEFAULT_MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS = 60 * 60 * 1000; // 1h
|
||||
int _MINIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS = DEFAULT_MINIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS; // 45m
|
||||
int _MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS = DEFAULT_MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS; // 1h
|
||||
QTimer _dynamicDomainVerificationTimer;
|
||||
void startDynamicDomainVerification();
|
||||
};
|
||||
|
||||
#endif // hifi_EntityServer_h
|
||||
|
|
|
@ -92,7 +92,19 @@ void OctreeInboundPacketProcessor::processPacket(QSharedPointer<ReceivedMessage>
|
|||
// Ask our tree subclass if it can handle the incoming packet...
|
||||
PacketType packetType = message->getType();
|
||||
|
||||
if (_myServer->getOctree()->handlesEditPacketType(packetType)) {
|
||||
if (packetType == PacketType::ChallengeOwnership) {
|
||||
_myServer->getOctree()->withWriteLock([&] {
|
||||
_myServer->getOctree()->processChallengeOwnershipPacket(*message, sendingNode);
|
||||
});
|
||||
} else if (packetType == PacketType::ChallengeOwnershipRequest) {
|
||||
_myServer->getOctree()->withWriteLock([&] {
|
||||
_myServer->getOctree()->processChallengeOwnershipRequestPacket(*message, sendingNode);
|
||||
});
|
||||
} else if (packetType == PacketType::ChallengeOwnershipReply) {
|
||||
_myServer->getOctree()->withWriteLock([&] {
|
||||
_myServer->getOctree()->processChallengeOwnershipReplyPacket(*message, sendingNode);
|
||||
});
|
||||
} else if (_myServer->getOctree()->handlesEditPacketType(packetType)) {
|
||||
PerformanceWarning warn(debugProcessPacket, "processPacket KNOWN TYPE", debugProcessPacket);
|
||||
_receivedPacketCount++;
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include <HTTPConnection.h>
|
||||
#include <LogHandler.h>
|
||||
#include <shared/NetworkUtils.h>
|
||||
#include <NetworkingConstants.h>
|
||||
#include <NumericalConstants.h>
|
||||
#include <UUID.h>
|
||||
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
#include <UUID.h>
|
||||
#include <WebSocketServerClass.h>
|
||||
|
||||
#include <EntityScriptClient.h> // for EntityScriptServerServices
|
||||
|
||||
#include "EntityScriptServerLogging.h"
|
||||
#include "../entities/AssignmentParentFinder.h"
|
||||
|
||||
|
@ -68,6 +70,9 @@ EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssig
|
|||
DependencyManager::set<ScriptCache>();
|
||||
DependencyManager::set<ScriptEngines>(ScriptEngine::ENTITY_SERVER_SCRIPT);
|
||||
|
||||
DependencyManager::set<EntityScriptServerServices>();
|
||||
|
||||
|
||||
// Needed to ensure the creation of the DebugDraw instance on the main thread
|
||||
DebugDraw::getInstance();
|
||||
|
||||
|
@ -85,6 +90,7 @@ EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssig
|
|||
packetReceiver.registerListener(PacketType::ReloadEntityServerScript, this, "handleReloadEntityServerScriptPacket");
|
||||
packetReceiver.registerListener(PacketType::EntityScriptGetStatus, this, "handleEntityScriptGetStatusPacket");
|
||||
packetReceiver.registerListener(PacketType::EntityServerScriptLog, this, "handleEntityServerScriptLogPacket");
|
||||
packetReceiver.registerListener(PacketType::EntityScriptCallMethod, this, "handleEntityScriptCallMethodPacket");
|
||||
|
||||
static const int LOG_INTERVAL = MSECS_PER_SECOND / 10;
|
||||
auto timer = new QTimer(this);
|
||||
|
@ -231,6 +237,27 @@ void EntityScriptServer::pushLogs() {
|
|||
}
|
||||
}
|
||||
|
||||
void EntityScriptServer::handleEntityScriptCallMethodPacket(QSharedPointer<ReceivedMessage> receivedMessage, SharedNodePointer senderNode) {
|
||||
|
||||
if (_entitiesScriptEngine && _entityViewer.getTree() && !_shuttingDown) {
|
||||
auto entityID = QUuid::fromRfc4122(receivedMessage->read(NUM_BYTES_RFC4122_UUID));
|
||||
|
||||
auto method = receivedMessage->readString();
|
||||
|
||||
quint16 paramCount;
|
||||
receivedMessage->readPrimitive(¶mCount);
|
||||
|
||||
QStringList params;
|
||||
for (int param = 0; param < paramCount; param++) {
|
||||
auto paramString = receivedMessage->readString();
|
||||
params << paramString;
|
||||
}
|
||||
|
||||
_entitiesScriptEngine->callEntityScriptMethod(entityID, method, params, senderNode->getUUID());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void EntityScriptServer::run() {
|
||||
// make sure we request our script once the agent connects to the domain
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
@ -561,6 +588,7 @@ void EntityScriptServer::aboutToFinish() {
|
|||
// cleanup the AudioInjectorManager (and any still running injectors)
|
||||
DependencyManager::destroy<AudioInjectorManager>();
|
||||
DependencyManager::destroy<ScriptEngines>();
|
||||
DependencyManager::destroy<EntityScriptServerServices>();
|
||||
|
||||
// cleanup codec & encoder
|
||||
if (_codec && _encoder) {
|
||||
|
|
|
@ -54,6 +54,9 @@ private slots:
|
|||
|
||||
void pushLogs();
|
||||
|
||||
void handleEntityScriptCallMethodPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
|
||||
|
||||
|
||||
private:
|
||||
void negotiateAudioFormat();
|
||||
void selectAudioFormat(const QString& selectedCodecName);
|
||||
|
|
11
cmake/externals/draco/CMakeLists.txt
vendored
|
@ -13,7 +13,7 @@ ExternalProject_Add(
|
|||
${EXTERNAL_NAME}
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/draco-1.1.0.zip
|
||||
URL_MD5 208f8b04c91d5f1c73d731a3ea37c5bb
|
||||
CONFIGURE_COMMAND CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> ${EXTRA_CMAKE_FLAGS}
|
||||
CONFIGURE_COMMAND CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>-$<CONFIG> ${EXTRA_CMAKE_FLAGS}
|
||||
LOG_DOWNLOAD 1
|
||||
LOG_CONFIGURE 1
|
||||
LOG_BUILD 1
|
||||
|
@ -23,10 +23,11 @@ ExternalProject_Add(
|
|||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
||||
set(SUFFIXED_INSTALL_DIR "${INSTALL_DIR}-$<CONFIG>")
|
||||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${INSTALL_DIR}/include CACHE PATH "List of Draco include directories")
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SUFFIXED_INSTALL_DIR}/include CACHE PATH "List of Draco include directories")
|
||||
|
||||
if (UNIX)
|
||||
set(LIB_PREFIX "lib")
|
||||
|
@ -35,6 +36,6 @@ elseif (WIN32)
|
|||
set(LIB_EXT "lib")
|
||||
endif ()
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY ${INSTALL_DIR}/lib/${LIB_PREFIX}draco.${LIB_EXT} CACHE FILEPATH "Path to Draco release library")
|
||||
set(${EXTERNAL_NAME_UPPER}_ENCODER_LIBRARY ${INSTALL_DIR}/lib/${LIB_PREFIX}dracoenc.${LIB_EXT} CACHE FILEPATH "Path to Draco encoder release library")
|
||||
set(${EXTERNAL_NAME_UPPER}_DECODER_LIBRARY ${INSTALL_DIR}/lib/${LIB_PREFIX}dracodec.${LIB_EXT} CACHE FILEPATH "Path to Draco decoder release library")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY ${SUFFIXED_INSTALL_DIR}/lib/${LIB_PREFIX}draco.${LIB_EXT} CACHE FILEPATH "Path to Draco release library")
|
||||
set(${EXTERNAL_NAME_UPPER}_ENCODER_LIBRARY ${SUFFIXED_INSTALL_DIR}/lib/${LIB_PREFIX}dracoenc.${LIB_EXT} CACHE FILEPATH "Path to Draco encoder release library")
|
||||
set(${EXTERNAL_NAME_UPPER}_DECODER_LIBRARY ${SUFFIXED_INSTALL_DIR}/lib/${LIB_PREFIX}dracodec.${LIB_EXT} CACHE FILEPATH "Path to Draco decoder release library")
|
||||
|
|
2
cmake/externals/glew/CMakeLists.txt
vendored
|
@ -9,7 +9,7 @@ ExternalProject_Add(
|
|||
${EXTERNAL_NAME}
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/glew_simple_1.13.0.zip
|
||||
URL_MD5 73f833649e904257b35bf4e84f8bdfb5
|
||||
CONFIGURE_COMMAND CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
|
||||
CONFIGURE_COMMAND CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -DCMAKE_POSITION_INDEPENDENT_CODE=ON
|
||||
LOG_DOWNLOAD 1
|
||||
LOG_CONFIGURE 1
|
||||
LOG_BUILD 1
|
||||
|
|
2
cmake/externals/nvtt/CMakeLists.txt
vendored
|
@ -31,7 +31,7 @@ else ()
|
|||
${EXTERNAL_NAME}
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/nvidia-texture-tools-2.1.0.hifi.zip
|
||||
URL_MD5 5794b950f8b265a9a41b2839b3bf7ebb
|
||||
CONFIGURE_COMMAND CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DNVTT_SHARED=1 -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
|
||||
CONFIGURE_COMMAND CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DNVTT_SHARED=1 -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -DCMAKE_POSITION_INDEPENDENT_CODE=ON
|
||||
LOG_DOWNLOAD 1
|
||||
LOG_CONFIGURE 1
|
||||
LOG_BUILD 1
|
||||
|
|
|
@ -118,6 +118,7 @@ macro(AUTOSCRIBE_SHADER_LIB)
|
|||
foreach(SHADER_FILE ${SHADER_SOURCE_FILES})
|
||||
AUTOSCRIBE_SHADER(${SHADER_FILE} ${SHADER_INCLUDE_FILES})
|
||||
file(TO_CMAKE_PATH "${AUTOSCRIBE_SHADER_RETURN}" AUTOSCRIBE_GENERATED_FILE)
|
||||
set_property(SOURCE ${AUTOSCRIBE_GENERATED_FILE} PROPERTY SKIP_AUTOMOC ON)
|
||||
list(APPEND AUTOSCRIBE_SHADER_SRC ${AUTOSCRIBE_GENERATED_FILE})
|
||||
endforeach()
|
||||
#message(${TARGET_NAME} ${AUTOSCRIBE_SHADER_SRC})
|
||||
|
|
20
cmake/macros/GenerateQrc.cmake
Normal file
|
@ -0,0 +1,20 @@
|
|||
|
||||
function(GENERATE_QRC)
|
||||
set(oneValueArgs OUTPUT PREFIX PATH)
|
||||
set(multiValueArgs GLOBS)
|
||||
cmake_parse_arguments(GENERATE_QRC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
|
||||
if ("${GENERATE_QRC_PREFIX}" STREQUAL "")
|
||||
set(QRC_PREFIX_PATH /)
|
||||
else()
|
||||
set(QRC_PREFIX_PATH ${GENERATE_QRC_PREFIX})
|
||||
endif()
|
||||
|
||||
foreach(GLOB ${GENERATE_QRC_GLOBS})
|
||||
file(GLOB_RECURSE FOUND_FILES RELATIVE ${GENERATE_QRC_PATH} ${GLOB})
|
||||
foreach(FILENAME ${FOUND_FILES})
|
||||
set(QRC_CONTENTS "${QRC_CONTENTS}<file alias=\"${FILENAME}\">${GENERATE_QRC_PATH}/${FILENAME}</file>\n")
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
configure_file("${HF_CMAKE_DIR}/templates/resources.qrc.in" ${GENERATE_QRC_OUTPUT})
|
||||
endfunction()
|
|
@ -14,9 +14,17 @@ endif ()
|
|||
|
||||
if (HIFI_MEMORY_DEBUGGING)
|
||||
if (UNIX)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -U_FORTIFY_SOURCE -fno-stack-protector -fno-omit-frame-pointer")
|
||||
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libasan -static-libstdc++ -fsanitize=address")
|
||||
SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libasan -static-libstdc++ -fsanitize=address")
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
# for clang on Linux
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-omit-frame-pointer -fsanitize=undefined -fsanitize=address -fsanitize-recover=address")
|
||||
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=undefined -fsanitize=address -fsanitize-recover=address")
|
||||
SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=undefined -fsanitize=address -fsanitize-recover=address")
|
||||
else ()
|
||||
# for gcc on Linux
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -fsanitize=address -U_FORTIFY_SOURCE -fno-stack-protector -fno-omit-frame-pointer")
|
||||
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libasan -static-libstdc++ -fsanitize=undefined -fsanitize=address")
|
||||
SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libasan -static-libstdc++ -fsanitize=undefined -fsanitize=address")
|
||||
endif()
|
||||
endif (UNIX)
|
||||
endif ()
|
||||
endmacro(SETUP_MEMORY_DEBUGGER)
|
||||
|
|
|
@ -7,10 +7,12 @@
|
|||
#
|
||||
|
||||
function(set_from_env _RESULT_NAME _ENV_VAR_NAME _DEFAULT_VALUE)
|
||||
if ("$ENV{${_ENV_VAR_NAME}}" STREQUAL "")
|
||||
set (${_RESULT_NAME} ${_DEFAULT_VALUE} PARENT_SCOPE)
|
||||
else()
|
||||
set (${_RESULT_NAME} $ENV{${_ENV_VAR_NAME}} PARENT_SCOPE)
|
||||
if (NOT DEFINED ${_RESULT_NAME})
|
||||
if ("$ENV{${_ENV_VAR_NAME}}" STREQUAL "")
|
||||
set (${_RESULT_NAME} ${_DEFAULT_VALUE} PARENT_SCOPE)
|
||||
else()
|
||||
set (${_RESULT_NAME} $ENV{${_ENV_VAR_NAME}} PARENT_SCOPE)
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ if (WIN32 AND NOT CYGWIN)
|
|||
select_library_configurations(LIB_EAY)
|
||||
select_library_configurations(SSL_EAY)
|
||||
set(OPENSSL_LIBRARIES ${SSL_EAY_LIBRARY} ${LIB_EAY_LIBRARY})
|
||||
find_path(OPENSSL_DLL_PATH NAMES ssleay32.dll PATH_SUFFIXES "bin" ${_OPENSSL_ROOT_HINTS_AND_PATHS})
|
||||
find_path(OPENSSL_DLL_PATH NAMES ssleay32.dll PATH_SUFFIXES "bin" HINTS ${_OPENSSL_ROOT_HINTS_AND_PATHS} NO_DEFAULT_PATH)
|
||||
endif()
|
||||
else()
|
||||
|
||||
|
|
5
cmake/templates/resources.qrc.in
Normal file
|
@ -0,0 +1,5 @@
|
|||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource prefix="@QRC_PREFIX_PATH@">
|
||||
@QRC_CONTENTS@
|
||||
</qresource>
|
||||
</RCC>
|
|
@ -1,6 +1,12 @@
|
|||
{
|
||||
"version": 1.8,
|
||||
"version": 2.0,
|
||||
"settings": [
|
||||
{
|
||||
"name": "label",
|
||||
"label": "Label",
|
||||
"settings": [
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "metaverse",
|
||||
"label": "Metaverse / Networking",
|
||||
|
@ -14,7 +20,8 @@
|
|||
{
|
||||
"name": "id",
|
||||
"label": "Domain ID",
|
||||
"help": "This is your High Fidelity domain ID. If you do not want your domain to be registered in the High Fidelity metaverse you can leave this blank."
|
||||
"help": "This is your High Fidelity domain ID. If you do not want your domain to be registered in the High Fidelity metaverse you can leave this blank.",
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
"name": "automatic_networking",
|
||||
|
@ -82,11 +89,13 @@
|
|||
{
|
||||
"name": "description",
|
||||
"label": "Description",
|
||||
"advanced": true,
|
||||
"help": "A description of your domain (256 character limit)."
|
||||
},
|
||||
{
|
||||
"name": "maturity",
|
||||
"label": "Maturity",
|
||||
"advanced": true,
|
||||
"help": "A maturity rating, available as a guideline for content on your domain.",
|
||||
"default": "unrated",
|
||||
"type": "select",
|
||||
|
@ -116,6 +125,7 @@
|
|||
{
|
||||
"name": "hosts",
|
||||
"label": "Hosts",
|
||||
"advanced": true,
|
||||
"type": "table",
|
||||
"can_add_new_rows": true,
|
||||
"help": "Usernames of hosts who can reliably show your domain to new visitors.",
|
||||
|
@ -131,6 +141,7 @@
|
|||
{
|
||||
"name": "tags",
|
||||
"label": "Tags",
|
||||
"advanced": true,
|
||||
"type": "table",
|
||||
"can_add_new_rows": true,
|
||||
"help": "Common categories under which your domain falls.",
|
||||
|
@ -207,7 +218,7 @@
|
|||
"name": "standard_permissions",
|
||||
"type": "table",
|
||||
"label": "Domain-Wide User Permissions",
|
||||
"help": "Indicate which types of users can have which <a data-toggle='tooltip' data-html=true title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether a user can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether a user change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether a user can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether a user can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether a user can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether a user can replace entire content sets by wiping existing domain content.</li></ul><p>Note that permissions assigned to a specific user will supersede any parameter-level permissions that might otherwise apply to that user. Additionally, if more than one parameter is applicable to a given user, the permissions given to that user will be the sum of all applicable parameters. For example, let’s say only localhost users can connect and only logged in users can lock and unlock entities. If a user is both logged in and on localhost then they will be able to both connect and lock/unlock entities.</p>'>domain-wide permissions</a>.",
|
||||
"help": "Indicate which types of users can have which <a data-toggle='tooltip' data-html=true title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether a user can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether a user change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether a user can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether a user can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether a user can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether a user can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether a user can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether a user can replace entire content sets by wiping existing domain content.</li></ul><p>Note that permissions assigned to a specific user will supersede any parameter-level permissions that might otherwise apply to that user. Additionally, if more than one parameter is applicable to a given user, the permissions given to that user will be the sum of all applicable parameters. For example, let’s say only localhost users can connect and only logged in users can lock and unlock entities. If a user is both logged in and on localhost then they will be able to both connect and lock/unlock entities.</p>'>domain-wide permissions</a>.",
|
||||
"caption": "Standard Permissions",
|
||||
"can_add_new_rows": false,
|
||||
"groups": [
|
||||
|
@ -216,8 +227,8 @@
|
|||
"span": 1
|
||||
},
|
||||
{
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether a user can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether a user change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether a user can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether a user can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether a user can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether a user can replace entire content sets by wiping existing domain content.</li></ul><p>Note that permissions assigned to a specific user will supersede any parameter-level permissions that might otherwise apply to that user. Additionally, if more than one parameter is applicable to a given user, the permissions given to that user will be the sum of all applicable parameters. For example, let’s say only localhost users can connect and only logged in users can lock and unlock entities. If a user is both logged in and on localhost then they will be able to both connect and lock/unlock entities.</p>'>?</a>",
|
||||
"span": 8
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether a user can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether a user change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether a user can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether a user can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether a user can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether a user can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether a user can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether a user can replace entire content sets by wiping existing domain content.</li></ul><p>Note that permissions assigned to a specific user will supersede any parameter-level permissions that might otherwise apply to that user. Additionally, if more than one parameter is applicable to a given user, the permissions given to that user will be the sum of all applicable parameters. For example, let’s say only localhost users can connect and only logged in users can lock and unlock entities. If a user is both logged in and on localhost then they will be able to both connect and lock/unlock entities.</p>'>?</a>",
|
||||
"span": 10
|
||||
}
|
||||
],
|
||||
"columns": [
|
||||
|
@ -253,6 +264,20 @@
|
|||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_rez_certified",
|
||||
"label": "Rez Certified",
|
||||
"type": "checkbox",
|
||||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_rez_tmp_certified",
|
||||
"label": "Rez Temporary Certified",
|
||||
"type": "checkbox",
|
||||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_write_to_asset_server",
|
||||
"label": "Write Assets",
|
||||
|
@ -283,7 +308,7 @@
|
|||
}
|
||||
],
|
||||
"non-deletable-row-key": "permissions_id",
|
||||
"non-deletable-row-values": ["localhost", "anonymous", "logged-in"]
|
||||
"non-deletable-row-values": [ "localhost", "anonymous", "logged-in" ]
|
||||
},
|
||||
{
|
||||
"name": "group_permissions",
|
||||
|
@ -300,8 +325,8 @@
|
|||
"span": 1
|
||||
},
|
||||
{
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users in specific groups can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users in specific groups can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users in specific groups can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users in specific groups can create new entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users in specific groups can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether user in specific groups can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether a user can replace entire content sets by wiping existing domain content.</li></ul><p>Permissions granted to a specific user will be a union of the permissions granted to the groups they are in, as well as permissions from the previous section. Group permissions are only granted if the user doesn’t have their own row in the per-account section, below.</p>'>?</a>",
|
||||
"span": 8
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users in specific groups can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users in specific groups can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users in specific groups can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users in specific groups can create new entities with a finite lifetime.</li><li><strong>Rez Temporary</strong><br />Sets whether users in specific groups can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether a users in specific groups can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether a user can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users in specific groups can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether user in specific groups can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether a user can replace entire content sets by wiping existing domain content.</li></ul><p>Permissions granted to a specific user will be a union of the permissions granted to the groups they are in, as well as permissions from the previous section. Group permissions are only granted if the user doesn’t have their own row in the per-account section, below.</p>'>?</a>",
|
||||
"span": 10
|
||||
}
|
||||
],
|
||||
"columns": [
|
||||
|
@ -362,6 +387,20 @@
|
|||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_rez_certified",
|
||||
"label": "Rez Certified",
|
||||
"type": "checkbox",
|
||||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_rez_tmp_certified",
|
||||
"label": "Rez Temporary Certified",
|
||||
"type": "checkbox",
|
||||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_write_to_asset_server",
|
||||
"label": "Write Assets",
|
||||
|
@ -383,7 +422,7 @@
|
|||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
{
|
||||
"name": "id_can_replace_content",
|
||||
"label": "Replace Content",
|
||||
"type": "checkbox",
|
||||
|
@ -407,8 +446,8 @@
|
|||
"span": 1
|
||||
},
|
||||
{
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users in specific groups can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users in specific groups can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users in specific groups can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users in specific groups can create new entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users in specific groups can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether user in specific groups can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether users in specific groups can replace entire content sets by wiping existing domain content.</li></ul><p>Permissions granted to a specific user will be a union of the permissions granted to the groups they are in. Group permissions are only granted if the user doesn’t have their own row in the per-account section, below.</p>'>?</a>",
|
||||
"span": 8
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users in specific groups can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users in specific groups can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users in specific groups can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users in specific groups can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether a users in specific groups can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether a user can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users in specific groups can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether user in specific groups can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether users in specific groups can replace entire content sets by wiping existing domain content.</li></ul><p>Permissions granted to a specific user will be a union of the permissions granted to the groups they are in. Group permissions are only granted if the user doesn’t have their own row in the per-account section, below.</p>'>?</a>",
|
||||
"span": 10
|
||||
}
|
||||
],
|
||||
"columns": [
|
||||
|
@ -466,6 +505,20 @@
|
|||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_rez_certified",
|
||||
"label": "Rez Certified",
|
||||
"type": "checkbox",
|
||||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_rez_tmp_certified",
|
||||
"label": "Rez Temporary Certified",
|
||||
"type": "checkbox",
|
||||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_write_to_asset_server",
|
||||
"label": "Write Assets",
|
||||
|
@ -487,7 +540,7 @@
|
|||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
{
|
||||
"name": "id_can_replace_content",
|
||||
"label": "Replace Content",
|
||||
"type": "checkbox",
|
||||
|
@ -507,8 +560,8 @@
|
|||
"span": 1
|
||||
},
|
||||
{
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether a user can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether a user change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether a user can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether a user can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether a user can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether a user can replace entire content sets by wiping existing domain content.</li></ul><p>Note that permissions assigned to a specific user will supersede any parameter-level or group permissions that might otherwise apply to that user.</p>'>?</a>",
|
||||
"span": 8
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether a user can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether a user change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether a user can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether a user can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether a user can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether a user can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether a user can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether a user can replace entire content sets by wiping existing domain content.</li></ul><p>Note that permissions assigned to a specific user will supersede any parameter-level or group permissions that might otherwise apply to that user.</p>'>?</a>",
|
||||
"span": 10
|
||||
}
|
||||
],
|
||||
"columns": [
|
||||
|
@ -544,6 +597,20 @@
|
|||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_rez_certified",
|
||||
"label": "Rez Certified",
|
||||
"type": "checkbox",
|
||||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_rez_tmp_certified",
|
||||
"label": "Rez Temporary Certified",
|
||||
"type": "checkbox",
|
||||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_write_to_asset_server",
|
||||
"label": "Write Assets",
|
||||
|
@ -565,7 +632,7 @@
|
|||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
{
|
||||
"name": "id_can_replace_content",
|
||||
"label": "Replace Content",
|
||||
"type": "checkbox",
|
||||
|
@ -585,8 +652,8 @@
|
|||
"span": 1
|
||||
},
|
||||
{
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide IP Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users from specific IPs can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users from specific IPs can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users from specific IPs can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users from specific IPs can create new entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users from specific IPs can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether users from specific IPs can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether users from specific IPs can replace entire content sets by wiping existing domain content.</li></ul><p>Note that permissions assigned to a specific IP will supersede any parameter-level permissions that might otherwise apply to that user (from groups or standard permissions above). IP address permissions are overriden if the user has their own row in the users section.</p>'>?</a>",
|
||||
"span": 8
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide IP Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users from specific IPs can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users from specific IPs can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users from specific IPs can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users from specific IPs can create new entities with a finite lifetime.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether users from specific IPs can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether users from specific IPs can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users from specific IPs can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether users from specific IPs can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether users from specific IPs can replace entire content sets by wiping existing domain content.</li></ul><p>Note that permissions assigned to a specific IP will supersede any parameter-level permissions that might otherwise apply to that user (from groups or standard permissions above). IP address permissions are overriden if the user has their own row in the users section.</p>'>?</a>",
|
||||
"span": 10
|
||||
}
|
||||
],
|
||||
"columns": [
|
||||
|
@ -622,6 +689,20 @@
|
|||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_rez_certified",
|
||||
"label": "Rez Certified",
|
||||
"type": "checkbox",
|
||||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_rez_tmp_certified",
|
||||
"label": "Rez Temporary Certified",
|
||||
"type": "checkbox",
|
||||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_write_to_asset_server",
|
||||
"label": "Write Assets",
|
||||
|
@ -643,7 +724,7 @@
|
|||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
{
|
||||
"name": "id_can_replace_content",
|
||||
"label": "Replace Content",
|
||||
"type": "checkbox",
|
||||
|
@ -663,8 +744,8 @@
|
|||
"span": 1
|
||||
},
|
||||
{
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide MAC Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users with specific MACs can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users from specific MACs can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users with specific MACs can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users with specific MACs can create new entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users with specific MACs can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether users with specific MACs can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether users with specific MACs can replace entire content sets by wiping existing domain content.</li></ul><p>Note that permissions assigned to a specific MAC will supersede any parameter-level permissions that might otherwise apply to that user (from groups or standard permissions above). MAC address permissions are overriden if the user has their own row in the users section.</p>'>?</a>",
|
||||
"span": 8
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide MAC Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users with specific MACs can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users from specific MACs can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users with specific MACs can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users with specific MACs can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether users with specific MACs can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether users with specific MACs can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users with specific MACs can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether users with specific MACs can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether users with specific MACs can replace entire content sets by wiping existing domain content.</li></ul><p>Note that permissions assigned to a specific MAC will supersede any parameter-level permissions that might otherwise apply to that user (from groups or standard permissions above). MAC address permissions are overriden if the user has their own row in the users section.</p>'>?</a>",
|
||||
"span": 10
|
||||
}
|
||||
],
|
||||
"columns": [
|
||||
|
@ -700,6 +781,20 @@
|
|||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_rez_certified",
|
||||
"label": "Rez Certified",
|
||||
"type": "checkbox",
|
||||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_rez_tmp_certified",
|
||||
"label": "Rez Temporary Certified",
|
||||
"type": "checkbox",
|
||||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_write_to_asset_server",
|
||||
"label": "Write Assets",
|
||||
|
@ -721,7 +816,7 @@
|
|||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
{
|
||||
"name": "id_can_replace_content",
|
||||
"label": "Replace Content",
|
||||
"type": "checkbox",
|
||||
|
@ -741,8 +836,8 @@
|
|||
"span": 1
|
||||
},
|
||||
{
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide Machine Fingerprint Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users with specific Machine Fingerprints can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users from specific Machine Fingerprints can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users with specific Machine Fingerprints can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users with specific Machine Fingerprints can create new entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users with specific Machine Fingerprints can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether users with specific Machine Fingerprints can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether users with specific Machine Fingerprints can replace entire content sets by wiping existing domain content.</li></ul><p>Note that permissions assigned to a specific Machine Fingerprint will supersede any parameter-level permissions that might otherwise apply to that user (from groups or standard permissions above). Machine Fingerprint address permissions are overriden if the user has their own row in the users section.</p>'>?</a>",
|
||||
"span": 8
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide Machine Fingerprint Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users with specific Machine Fingerprints can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users from specific Machine Fingerprints can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users with specific Machine Fingerprints can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users with specific Machine Fingerprints can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether users with specific Machine Fingerprints can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether users with specific Machine Fingerprints can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users with specific Machine Fingerprints can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether users with specific Machine Fingerprints can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether users with specific Machine Fingerprints can replace entire content sets by wiping existing domain content.</li></ul><p>Note that permissions assigned to a specific Machine Fingerprint will supersede any parameter-level permissions that might otherwise apply to that user (from groups or standard permissions above). Machine Fingerprint address permissions are overriden if the user has their own row in the users section.</p>'>?</a>",
|
||||
"span": 10
|
||||
}
|
||||
],
|
||||
"columns": [
|
||||
|
@ -778,6 +873,20 @@
|
|||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_rez_certified",
|
||||
"label": "Rez Certified",
|
||||
"type": "checkbox",
|
||||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_rez_tmp_certified",
|
||||
"label": "Rez Temporary Certified",
|
||||
"type": "checkbox",
|
||||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_write_to_asset_server",
|
||||
"label": "Write Assets",
|
||||
|
@ -799,7 +908,7 @@
|
|||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
{
|
||||
"name": "id_can_replace_content",
|
||||
"label": "Replace Content",
|
||||
"type": "checkbox",
|
||||
|
@ -841,7 +950,7 @@
|
|||
{
|
||||
"name": "asset_server",
|
||||
"label": "Asset Server (ATP)",
|
||||
"assignment-types": [3],
|
||||
"assignment-types": [ 3 ],
|
||||
"settings": [
|
||||
{
|
||||
"name": "enabled",
|
||||
|
@ -858,13 +967,21 @@
|
|||
"help": "The path to the directory assets are stored in.<br/>If this path is relative, it will be relative to the application data directory.<br/>If you change this path you will need to manually copy any existing assets from the previous directory.",
|
||||
"default": "",
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
"name": "assets_filesize_limit",
|
||||
"type": "int",
|
||||
"label": "File Size Limit",
|
||||
"help": "The file size limit of an asset that can be imported into the asset server in MBytes. 0 (default) means no limit on file size.",
|
||||
"default": 0,
|
||||
"advanced": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "entity_script_server",
|
||||
"label": "Entity Script Server (ESS)",
|
||||
"assignment-types": [5],
|
||||
"assignment-types": [ 5 ],
|
||||
"settings": [
|
||||
{
|
||||
"name": "entity_pps_per_script",
|
||||
|
@ -887,7 +1004,7 @@
|
|||
{
|
||||
"name": "avatars",
|
||||
"label": "Avatars",
|
||||
"assignment-types": [1, 2],
|
||||
"assignment-types": [ 1, 2 ],
|
||||
"settings": [
|
||||
{
|
||||
"name": "min_avatar_scale",
|
||||
|
@ -926,7 +1043,7 @@
|
|||
{
|
||||
"name": "audio_threading",
|
||||
"label": "Audio Threading",
|
||||
"assignment-types": [0],
|
||||
"assignment-types": [ 0 ],
|
||||
"settings": [
|
||||
{
|
||||
"name": "auto_threads",
|
||||
|
@ -949,7 +1066,7 @@
|
|||
{
|
||||
"name": "audio_env",
|
||||
"label": "Audio Environment",
|
||||
"assignment-types": [0],
|
||||
"assignment-types": [ 0 ],
|
||||
"settings": [
|
||||
{
|
||||
"name": "attenuation_per_doubling_in_distance",
|
||||
|
@ -1156,6 +1273,22 @@
|
|||
"default": "3600",
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
"name": "dynamicDomainVerificationTimeMin",
|
||||
"label": "Dynamic Domain Verification Time (seconds) - Minimum",
|
||||
"help": "The lower limit on the amount of time that passes before Dynamic Domain Verification on entities occurs. Units are seconds.",
|
||||
"placeholder": "2700",
|
||||
"default": "2700",
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
"name": "dynamicDomainVerificationTimeMax",
|
||||
"label": "Dynamic Domain Verification Time (seconds) - Maximum",
|
||||
"help": "The upper limit on the amount of time that passes before Dynamic Domain Verification on entities occurs. Units are seconds.",
|
||||
"placeholder": "3600",
|
||||
"default": "3600",
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
"name": "entityScriptSourceWhitelist",
|
||||
"label": "Entity Scripts Allowed from:",
|
||||
|
@ -1503,6 +1636,29 @@
|
|||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "wizard",
|
||||
"label": "Setup Wizard",
|
||||
"restart": false,
|
||||
"hidden": true,
|
||||
"settings": [
|
||||
{
|
||||
"name": "cloud_domain",
|
||||
"type": "checkbox",
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "steps_completed",
|
||||
"type": "int",
|
||||
"default": 0
|
||||
},
|
||||
{
|
||||
"name": "completed_once",
|
||||
"type": "checkbox",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
body {
|
||||
position: relative;
|
||||
padding-bottom: 30px;
|
||||
margin-top: 70px;
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
|
@ -27,14 +28,14 @@ body {
|
|||
.table .value-row td,
|
||||
.table .value-category td,
|
||||
.table .inputs td {
|
||||
vertical-align: middle;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.table .table-checkbox {
|
||||
/* Fix IE sizing checkboxes to fill table cell */
|
||||
width: auto;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
/* Fix IE sizing checkboxes to fill table cell */
|
||||
width: auto;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.value-category:not(.inputs) {
|
||||
|
@ -80,8 +81,10 @@ span.port {
|
|||
}
|
||||
|
||||
#setup-sidebar.affix {
|
||||
position: fixed;
|
||||
top: 15px;
|
||||
/* This overrides a case where going to the bottom of the page,
|
||||
* then scrolling up, causes `position: relative` to be added to the style
|
||||
*/
|
||||
position: fixed !important;
|
||||
}
|
||||
|
||||
#setup-sidebar button {
|
||||
|
@ -145,55 +148,55 @@ table {
|
|||
}
|
||||
|
||||
caption {
|
||||
color: #333;
|
||||
font-weight: 700;
|
||||
padding-top: 0;
|
||||
color: #333;
|
||||
font-weight: 700;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
table > tbody > .headers > td {
|
||||
vertical-align: middle;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
table .headers + .headers td {
|
||||
font-size: 13px;
|
||||
color: #222;
|
||||
font-size: 13px;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
#security table .headers td + td {
|
||||
text-align: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tooltip.top .tooltip-arrow {
|
||||
border-top-color: #fff;
|
||||
border-width: 10px 10px 0;
|
||||
margin-bottom: -5px;
|
||||
border-top-color: #fff;
|
||||
border-width: 10px 10px 0;
|
||||
margin-bottom: -5px;
|
||||
}
|
||||
|
||||
.tooltip-inner {
|
||||
padding: 20px 20px 10px 20px;
|
||||
font-size: 14px;
|
||||
text-align: left;
|
||||
color: #333;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 3px 8px 8px #e8e8e8;
|
||||
padding: 20px 20px 10px 20px;
|
||||
font-size: 14px;
|
||||
text-align: left;
|
||||
color: #333;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 3px 8px 8px #e8e8e8;
|
||||
}
|
||||
|
||||
.tooltip.in {
|
||||
opacity: 1;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.tooltip-inner ul {
|
||||
padding-left: 0;
|
||||
margin-bottom: 15px;
|
||||
padding-left: 0;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.tooltip-inner li {
|
||||
list-style-type: none;
|
||||
margin-bottom: 5px;
|
||||
list-style-type: none;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
#security .tooltip-inner {
|
||||
max-width: 520px;
|
||||
max-width: 520px;
|
||||
}
|
||||
|
||||
#xs-advanced-container {
|
||||
|
@ -241,6 +244,20 @@ table .headers + .headers td {
|
|||
animation-delay: -0.16s;
|
||||
}
|
||||
|
||||
.col-centered {
|
||||
float: none;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.centered-hack-parent {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.centered-hack {
|
||||
text-align: left;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
@-webkit-keyframes bouncedelay {
|
||||
0%, 80%, 100% { -webkit-transform: scale(0.0) }
|
||||
40% { -webkit-transform: scale(1.0) }
|
||||
|
@ -255,3 +272,50 @@ table .headers + .headers td {
|
|||
-webkit-transform: scale(1.0);
|
||||
}
|
||||
}
|
||||
|
||||
/* From https://gist.github.com/alexandrevicenzi/680147013e902a4eaa5d */
|
||||
.glyphicon-refresh-animate {
|
||||
-animation: spin .7s infinite linear;
|
||||
-ms-animation: spin .7s infinite linear;
|
||||
-webkit-animation: spinw .7s infinite linear;
|
||||
-moz-animation: spinm .7s infinite linear;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
from { transform: scale(1) rotate(0deg); }
|
||||
to { transform: scale(1) rotate(360deg); }
|
||||
}
|
||||
|
||||
@-webkit-keyframes spinw {
|
||||
from { -webkit-transform: rotate(0deg); }
|
||||
to { -webkit-transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
@-moz-keyframes spinm {
|
||||
from { -moz-transform: rotate(0deg); }
|
||||
to { -moz-transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.warning-text {
|
||||
padding-top: 10px;
|
||||
color: #EB5757;
|
||||
}
|
||||
|
||||
.account-connected-header {
|
||||
color: #6FCF97;
|
||||
font-size: 30px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
#visit-domain-link,
|
||||
.blue-link {
|
||||
font-size: 14px;
|
||||
text-decoration-line: underline;
|
||||
font-weight: normal;
|
||||
color: #2F80ED;
|
||||
}
|
||||
|
||||
#manage-cloud-domains-link {
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
|
BIN
domain-server/resources/web/favicon.ico
Normal file
After Width: | Height: | Size: 5.3 KiB |
|
@ -13,7 +13,7 @@
|
|||
<script src='/js/sweetalert.min.js'></script>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-default" role="navigation">
|
||||
<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
|
||||
<div class="container-fluid">
|
||||
<!-- Brand and toggle get grouped for better mobile display -->
|
||||
<div class="navbar-header">
|
||||
|
@ -23,7 +23,6 @@
|
|||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="/">domain-server</a>
|
||||
</div>
|
||||
|
||||
<!-- Collect the nav links, forms, and other content for toggling -->
|
||||
|
@ -40,6 +39,7 @@
|
|||
<li><a href="/settings/">Settings</a></li>
|
||||
</ul>
|
||||
<ul class="nav navbar-right navbar-nav">
|
||||
<li><a id="visit-domain-link" target="_blank" style="display: none;">Visit domain in VR</a></li>
|
||||
<li><a href="#" id="restart-server"><span class="glyphicon glyphicon-refresh"></span> Restart</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
25
domain-server/resources/web/images/checkmark.svg
Normal file
|
@ -0,0 +1,25 @@
|
|||
<svg width="676" height="676" viewBox="0 0 676 676" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>CongratulationImage</title>
|
||||
<desc>Created using Figma</desc>
|
||||
<g id="Canvas" transform="matrix(4 0 0 4 -21208 -17980)">
|
||||
<g id="CongratulationImage">
|
||||
<g id="Ellipse">
|
||||
<use xlink:href="#path0_fill" transform="translate(5302 4495)" fill="#FFFFFF"/>
|
||||
<mask id="mask0_outline_ins">
|
||||
<use xlink:href="#path0_fill" fill="white" transform="translate(5302 4495)"/>
|
||||
</mask>
|
||||
<g mask="url(#mask0_outline_ins)">
|
||||
<use xlink:href="#path1_stroke_2x" transform="translate(5302 4495)" fill="#219653"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Vector 2">
|
||||
<use xlink:href="#path2_stroke" transform="translate(5355 4559)" fill="#219653"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<defs>
|
||||
<path id="path0_fill" d="M 169 84.5C 169 131.168 131.168 169 84.5 169C 37.8319 169 0 131.168 0 84.5C 0 37.8319 37.8319 0 84.5 0C 131.168 0 169 37.8319 169 84.5Z"/>
|
||||
<path id="path1_stroke_2x" d="M 154 84.5C 154 122.884 122.884 154 84.5 154L 84.5 184C 139.452 184 184 139.452 184 84.5L 154 84.5ZM 84.5 154C 46.1162 154 15 122.884 15 84.5L -15 84.5C -15 139.452 29.5477 184 84.5 184L 84.5 154ZM 15 84.5C 15 46.1162 46.1162 15 84.5 15L 84.5 -15C 29.5477 -15 -15 29.5477 -15 84.5L 15 84.5ZM 84.5 15C 122.884 15 154 46.1162 154 84.5L 184 84.5C 184 29.5477 139.452 -15 84.5 -15L 84.5 15Z"/>
|
||||
<path id="path2_stroke" d="M 5.18747 19.8031C 2.19593 16.9382 -2.5517 17.0408 -5.41666 20.0323C -8.28162 23.0238 -8.17901 27.7715 -5.18747 30.6364L 5.18747 19.8031ZM 20.6541 45L 15.4667 50.4167C 18.3816 53.2083 22.9831 53.1924 25.8787 50.3809L 20.6541 45ZM 72.2246 5.38085C 75.1964 2.49539 75.2663 -2.25283 72.3809 -5.2246C 69.4954 -8.19636 64.7472 -8.26632 61.7754 -5.38085L 72.2246 5.38085ZM -5.18747 30.6364L 15.4667 50.4167L 25.8416 39.5833L 5.18747 19.8031L -5.18747 30.6364ZM 25.8787 50.3809L 72.2246 5.38085L 61.7754 -5.38085L 15.4295 39.6191L 25.8787 50.3809Z"/>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 1.9 KiB |
|
@ -32,7 +32,6 @@ $(document).ready(function(){
|
|||
$('ul.nav a').filter(function() {
|
||||
return this.href == url;
|
||||
}).parent().addClass('active');
|
||||
|
||||
$('body').on('click', '#restart-server', function(e) {
|
||||
swal( {
|
||||
title: "Are you sure?",
|
||||
|
@ -46,4 +45,4 @@ $(document).ready(function(){
|
|||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
393
domain-server/resources/web/js/shared.js
Normal file
|
@ -0,0 +1,393 @@
|
|||
var Settings = {
|
||||
showAdvanced: false,
|
||||
ADVANCED_CLASS: 'advanced-setting',
|
||||
DEPRECATED_CLASS: 'deprecated-setting',
|
||||
TRIGGER_CHANGE_CLASS: 'trigger-change',
|
||||
DATA_ROW_CLASS: 'value-row',
|
||||
DATA_COL_CLASS: 'value-col',
|
||||
DATA_CATEGORY_CLASS: 'value-category',
|
||||
ADD_ROW_BUTTON_CLASS: 'add-row',
|
||||
ADD_ROW_SPAN_CLASSES: 'glyphicon glyphicon-plus add-row',
|
||||
DEL_ROW_BUTTON_CLASS: 'del-row',
|
||||
DEL_ROW_SPAN_CLASSES: 'glyphicon glyphicon-remove del-row',
|
||||
ADD_CATEGORY_BUTTON_CLASS: 'add-category',
|
||||
ADD_CATEGORY_SPAN_CLASSES: 'glyphicon glyphicon-plus add-category',
|
||||
TOGGLE_CATEGORY_COLUMN_CLASS: 'toggle-category',
|
||||
TOGGLE_CATEGORY_SPAN_CLASS: 'toggle-category-icon',
|
||||
TOGGLE_CATEGORY_SPAN_CLASSES: 'glyphicon toggle-category-icon',
|
||||
TOGGLE_CATEGORY_EXPANDED_CLASS: 'glyphicon-triangle-bottom',
|
||||
TOGGLE_CATEGORY_CONTRACTED_CLASS: 'glyphicon-triangle-right',
|
||||
DEL_CATEGORY_BUTTON_CLASS: 'del-category',
|
||||
DEL_CATEGORY_SPAN_CLASSES: 'glyphicon glyphicon-remove del-category',
|
||||
MOVE_UP_BUTTON_CLASS: 'move-up',
|
||||
MOVE_UP_SPAN_CLASSES: 'glyphicon glyphicon-chevron-up move-up',
|
||||
MOVE_DOWN_BUTTON_CLASS: 'move-down',
|
||||
MOVE_DOWN_SPAN_CLASSES: 'glyphicon glyphicon-chevron-down move-down',
|
||||
TABLE_BUTTONS_CLASS: 'buttons',
|
||||
ADD_DEL_BUTTONS_CLASS: 'add-del-buttons',
|
||||
ADD_DEL_BUTTONS_CLASSES: 'buttons add-del-buttons',
|
||||
REORDER_BUTTONS_CLASS: 'reorder-buttons',
|
||||
REORDER_BUTTONS_CLASSES: 'buttons reorder-buttons',
|
||||
NEW_ROW_CLASS: 'new-row',
|
||||
CONNECT_ACCOUNT_BTN_ID: 'connect-account-btn',
|
||||
DISCONNECT_ACCOUNT_BTN_ID: 'disconnect-account-btn',
|
||||
CREATE_DOMAIN_ID_BTN_ID: 'create-domain-btn',
|
||||
CHOOSE_DOMAIN_ID_BTN_ID: 'choose-domain-btn',
|
||||
GET_TEMPORARY_NAME_BTN_ID: 'get-temp-name-btn',
|
||||
DOMAIN_ID_SELECTOR: '[name="metaverse.id"]',
|
||||
ACCESS_TOKEN_SELECTOR: '[name="metaverse.access_token"]',
|
||||
PLACES_TABLE_ID: 'places-table',
|
||||
ADD_PLACE_BTN_ID: 'add-place-btn',
|
||||
FORM_ID: 'settings-form',
|
||||
INVALID_ROW_CLASS: 'invalid-input',
|
||||
DATA_ROW_INDEX: 'data-row-index'
|
||||
};
|
||||
|
||||
var URLs = {
|
||||
// STABLE METAVERSE_URL: https://metaverse.highfidelity.com
|
||||
// STAGING METAVERSE_URL: https://staging.highfidelity.com
|
||||
METAVERSE_URL: 'https://metaverse.highfidelity.com',
|
||||
PLACE_URL: 'https://hifi.place',
|
||||
};
|
||||
|
||||
var Strings = {
|
||||
LOADING_SETTINGS_ERROR: "There was a problem loading the domain settings.\nPlease refresh the page to try again.",
|
||||
|
||||
CHOOSE_DOMAIN_BUTTON: "Choose from my domains",
|
||||
CREATE_DOMAIN_BUTTON: "Create new domain ID",
|
||||
CREATE_DOMAIN_SUCCESS_JUST_CONNECTED: "We connnected your High Fidelity account and created a new domain ID for this machine.",
|
||||
CREATE_DOMAIN_SUCCESS: "We created a new domain ID for this machine.",
|
||||
|
||||
// When a place modification fails, they will be brought back to the previous
|
||||
// dialog with new path still set, allowing them to retry immediately, and without
|
||||
// having to type the new path in again.
|
||||
EDIT_PLACE_TITLE: "Modify Viewpoint or Path",
|
||||
EDIT_PLACE_ERROR: "Failed to update place path. Please try again.",
|
||||
EDIT_PLACE_CONFIRM_BUTTON: "Save",
|
||||
EDIT_PLACE_CONFIRM_BUTTON_PENDING: "Saving...",
|
||||
EDIT_PLACE_CANCEL_BUTTON: "Cancel",
|
||||
|
||||
REMOVE_PLACE_TITLE: "Are you sure you want to remove <strong>{{place}}</strong>?",
|
||||
REMOVE_PLACE_ERROR: "Failed to remove place. Please try again.",
|
||||
REMOVE_PLACE_DELETE_BUTTON: "Delete",
|
||||
REMOVE_PLACE_DELETE_BUTTON_PENDING: "Deleting...",
|
||||
REMOVE_PLACE_CANCEL_BUTTON: "Cancel",
|
||||
|
||||
ADD_PLACE_TITLE: "Choose a place",
|
||||
ADD_PLACE_MESSAGE: "Choose the High Fidelity place to point at this domain server.",
|
||||
ADD_PLACE_CONFIRM_BUTTON: "Choose place",
|
||||
ADD_PLACE_CONFIRM_BUTTON_PENDING: "Saving...",
|
||||
ADD_PLACE_CANCEL_BUTTON: "Cancel",
|
||||
ADD_PLACE_UNKNOWN_ERROR: "There was an error adding this place name.",
|
||||
|
||||
ADD_PLACE_NO_PLACES_MESSAGE: "<p>You do not have any places in your High Fidelity account."
|
||||
+ "<br/><br/>Go to your <a href='https://metaverse.highfidelity.com/user/places/new'>places page</a> to create a new one. Once your place is created re-open this dialog to select it.</p>",
|
||||
ADD_PLACE_NO_PLACES_BUTTON: "Create new place",
|
||||
ADD_PLACE_UNABLE_TO_LOAD_ERROR: "We were unable to load your place names. Please try again later.",
|
||||
ADD_PLACE_LOADING_DIALOG: "Loading your places...",
|
||||
|
||||
ADD_PLACE_NOT_CONNECTED_TITLE: "Access token required",
|
||||
ADD_PLACE_NOT_CONNECTED_MESSAGE: "You must have an access token to query your High Fidelity places.<br><br>Please follow the instructions on the settings page to add an access token.",
|
||||
};
|
||||
|
||||
var DOMAIN_ID_TYPE_NONE = 0;
|
||||
var DOMAIN_ID_TYPE_TEMP = 1;
|
||||
var DOMAIN_ID_TYPE_FULL = 2;
|
||||
var DOMAIN_ID_TYPE_UNKNOWN = 3;
|
||||
|
||||
function domainIDIsSet() {
|
||||
return Settings.data.values.metaverse.id.length > 0;
|
||||
}
|
||||
|
||||
function getCurrentDomainIDType() {
|
||||
if (!domainIDIsSet()) {
|
||||
return DOMAIN_ID_TYPE_NONE;
|
||||
}
|
||||
if (typeof DomainInfo === 'undefined') {
|
||||
return DOMAIN_ID_TYPE_UNKNOWN;
|
||||
}
|
||||
if (DomainInfo !== null) {
|
||||
if (DomainInfo.name !== undefined) {
|
||||
return DOMAIN_ID_TYPE_TEMP;
|
||||
}
|
||||
return DOMAIN_ID_TYPE_FULL;
|
||||
}
|
||||
return DOMAIN_ID_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
function showLoadingDialog(msg) {
|
||||
var message = '<div class="text-center">';
|
||||
message += '<span class="glyphicon glyphicon-refresh glyphicon-refresh-animate"></span> ' + msg;
|
||||
message += '</div>';
|
||||
|
||||
return bootbox.dialog({
|
||||
message: message,
|
||||
closeButton: false
|
||||
});
|
||||
}
|
||||
|
||||
function sendUpdatePlaceRequest(id, path, domainID, clearDomainID, onSuccess, onError) {
|
||||
var data = {
|
||||
place_id: id,
|
||||
path: path
|
||||
};
|
||||
if (domainID) {
|
||||
data.domain_id = domainID;
|
||||
}
|
||||
if (clearDomainID) {
|
||||
data.domain_id = null;
|
||||
}
|
||||
$.ajax({
|
||||
url: '/api/places',
|
||||
type: 'PUT',
|
||||
data: data,
|
||||
success: onSuccess,
|
||||
error: onError
|
||||
});
|
||||
}
|
||||
|
||||
function chooseFromHighFidelityPlaces(accessToken, forcePathTo, onSuccessfullyAdded) {
|
||||
if (accessToken) {
|
||||
|
||||
var loadingDialog = showLoadingDialog(Strings.ADD_PLACE_LOADING_DIALOG);
|
||||
|
||||
$.ajax("/api/places", {
|
||||
dataType: 'json',
|
||||
jsonp: false,
|
||||
success: function(data) {
|
||||
if (data.status == 'success') {
|
||||
var modal_buttons = {
|
||||
cancel: {
|
||||
label: Strings.ADD_PLACE_CANCEL_BUTTON,
|
||||
className: 'add-place-cancel-button btn-default'
|
||||
}
|
||||
};
|
||||
|
||||
var dialog;
|
||||
var modal_body;
|
||||
|
||||
if (data.data.places.length) {
|
||||
var places_by_id = {};
|
||||
|
||||
modal_body = $('<div>');
|
||||
|
||||
modal_body.append($("<p>Choose a place name that you own or <a href='" + URLs.METAVERSE_URL + "/user/places' target='_blank'>register a new place name</a></p>"));
|
||||
|
||||
var currentDomainIDType = getCurrentDomainIDType();
|
||||
if (currentDomainIDType === DOMAIN_ID_TYPE_TEMP) {
|
||||
var warning = "<div class='domain-loading-error alert alert-warning'>";
|
||||
warning += "If you choose a place name it will replace your current temporary place name.";
|
||||
warning += "</div>";
|
||||
modal_body.append(warning);
|
||||
}
|
||||
|
||||
// setup a select box for the returned places
|
||||
modal_body.append($("<label for='place-name-select'>Places</label>"));
|
||||
place_select = $("<select id='place-name-select' class='form-control'></select>");
|
||||
_.each(data.data.places, function(place) {
|
||||
places_by_id[place.id] = place;
|
||||
place_select.append("<option value='" + place.id + "'>" + place.name + "</option>");
|
||||
})
|
||||
modal_body.append(place_select);
|
||||
modal_body.append($("<p id='place-name-warning' class='warning-text' style='display: none'>This place name already points to a place or path. Saving this would overwrite the previous settings associated with it.</p>"));
|
||||
|
||||
if (forcePathTo === undefined || forcePathTo === null) {
|
||||
var path = "<div class='form-group'>";
|
||||
path += "<label for='place-path-input' class='control-label'>Path</label>";
|
||||
path += "<input type='text' id='place-path-input' class='form-control' value='/'>";
|
||||
path += "</div>";
|
||||
modal_body.append($(path));
|
||||
}
|
||||
|
||||
var place_select = modal_body.find("#place-name-select")
|
||||
place_select.change(function(ev) {
|
||||
var warning = modal_body.find("#place-name-warning");
|
||||
var place = places_by_id[$(this).val()];
|
||||
if (place === undefined || place.pointee === null) {
|
||||
warning.hide();
|
||||
} else {
|
||||
warning.show();
|
||||
}
|
||||
});
|
||||
place_select.trigger('change');
|
||||
|
||||
modal_buttons["success"] = {
|
||||
label: Strings.ADD_PLACE_CONFIRM_BUTTON,
|
||||
className: 'add-place-confirm-button btn btn-primary',
|
||||
callback: function() {
|
||||
var placeID = $('#place-name-select').val();
|
||||
// set the place ID on the form
|
||||
$(Settings.place_ID_SELECTOR).val(placeID).change();
|
||||
|
||||
if (forcePathTo === undefined || forcePathTo === null) {
|
||||
var placePath = $('#place-path-input').val();
|
||||
} else {
|
||||
var placePath = forcePathTo;
|
||||
}
|
||||
|
||||
$('.add-place-confirm-button').attr('disabled', 'disabled');
|
||||
$('.add-place-confirm-button').html(Strings.ADD_PLACE_CONFIRM_BUTTON_PENDING);
|
||||
$('.add-place-cancel-button').attr('disabled', 'disabled');
|
||||
|
||||
function finalizeSaveDomainID(domainID) {
|
||||
var jsonSettings = {
|
||||
metaverse: {
|
||||
id: domainID
|
||||
}
|
||||
}
|
||||
var dialog = showLoadingDialog("Waiting for Domain Server to restart...");
|
||||
$.ajax('/settings.json', {
|
||||
data: JSON.stringify(jsonSettings),
|
||||
contentType: 'application/json',
|
||||
type: 'POST'
|
||||
}).done(function(data) {
|
||||
if (data.status == "success") {
|
||||
waitForDomainServerRestart(function() {
|
||||
dialog.modal('hide');
|
||||
if (onSuccessfullyAdded) {
|
||||
onSuccessfullyAdded(places_by_id[placeID].name, domainID);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
bootbox.alert("Failed to add place");
|
||||
}
|
||||
}).fail(function() {
|
||||
bootbox.alert("Failed to add place");
|
||||
});
|
||||
}
|
||||
|
||||
function finishSettingUpPlace(domainID) {
|
||||
sendUpdatePlaceRequest(
|
||||
placeID,
|
||||
placePath,
|
||||
domainID,
|
||||
false,
|
||||
function(data) {
|
||||
$(Settings.DOMAIN_ID_SELECTOR).val(domainID).change();
|
||||
dialog.modal('hide')
|
||||
if (domainID) {
|
||||
finalizeSaveDomainID(domainID);
|
||||
} else {
|
||||
if (onSuccessfullyAdded) {
|
||||
onSuccessfullyAdded(places_by_id[placeID].name);
|
||||
}
|
||||
}
|
||||
},
|
||||
function(data) {
|
||||
$('.add-place-confirm-button').removeAttr('disabled');
|
||||
$('.add-place-confirm-button').html(Strings.ADD_PLACE_CONFIRM_BUTTON);
|
||||
$('.add-place-cancel-button').removeAttr('disabled');
|
||||
bootbox.alert(Strings.ADD_PLACE_UNKNOWN_ERROR);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (currentDomainIDType === DOMAIN_ID_TYPE_FULL) {
|
||||
finishSettingUpPlace();
|
||||
} else {
|
||||
sendCreateDomainRequest(function(domainID) {
|
||||
console.log("Created domain", domainID);
|
||||
finishSettingUpPlace(domainID);
|
||||
}, function() {
|
||||
$('.add-place-confirm-button').removeAttr('disabled');
|
||||
$('.add-place-confirm-button').html(Strings.ADD_PLACE_CONFIRM_BUTTON);
|
||||
$('.add-place-cancel-button').removeAttr('disabled');
|
||||
bootbox.alert(Strings.ADD_PLACE_UNKNOWN_ERROR);
|
||||
bootbox.alert("FAIL");
|
||||
});
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
modal_buttons["success"] = {
|
||||
label: Strings.ADD_PLACE_NO_PLACES_BUTTON,
|
||||
callback: function() {
|
||||
window.open(URLs.METAVERSE_URL + "/user/places", '_blank');
|
||||
}
|
||||
}
|
||||
modal_body = Strings.ADD_PLACE_NO_PLACES_MESSAGE;
|
||||
}
|
||||
|
||||
dialog = bootbox.dialog({
|
||||
title: Strings.ADD_PLACE_TITLE,
|
||||
message: modal_body,
|
||||
closeButton: false,
|
||||
buttons: modal_buttons
|
||||
});
|
||||
} else {
|
||||
bootbox.alert(Strings.ADD_PLACE_UNABLE_TO_LOAD_ERROR);
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
bootbox.alert(Strings.ADD_PLACE_UNABLE_TO_LOAD_ERROR);
|
||||
},
|
||||
complete: function() {
|
||||
loadingDialog.modal('hide');
|
||||
}
|
||||
});
|
||||
|
||||
} else {
|
||||
bootbox.alert({
|
||||
title: Strings.ADD_PLACE_NOT_CONNECTED_TITLE,
|
||||
message: Strings.ADD_PLACE_NOT_CONNECTED_MESSAGE
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function sendCreateDomainRequest(onSuccess, onError) {
|
||||
$.ajax({
|
||||
url: '/api/domains',
|
||||
dataType: 'json',
|
||||
type: 'POST',
|
||||
data: { label: "" },
|
||||
success: function(data) {
|
||||
onSuccess(data.domain.id);
|
||||
},
|
||||
error: onError
|
||||
});
|
||||
}
|
||||
|
||||
function waitForDomainServerRestart(callback) {
|
||||
function checkForDomainUp() {
|
||||
$.ajax('', {
|
||||
success: function() {
|
||||
callback();
|
||||
},
|
||||
error: function() {
|
||||
setTimeout(checkForDomainUp, 50);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
setTimeout(checkForDomainUp, 10);
|
||||
|
||||
}
|
||||
|
||||
function prepareAccessTokenPrompt(callback) {
|
||||
swal({
|
||||
title: "Connect Account",
|
||||
type: "input",
|
||||
text: "Paste your created access token here." +
|
||||
"</br></br>If you did not successfully create an access token click cancel below and attempt to connect your account again.</br></br>",
|
||||
showCancelButton: true,
|
||||
closeOnConfirm: false,
|
||||
html: true
|
||||
}, function(inputValue){
|
||||
if (inputValue === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (inputValue === "") {
|
||||
swal.showInputError("Please paste your access token in the input field.")
|
||||
return false
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
callback(inputValue);
|
||||
}
|
||||
|
||||
swal.close();
|
||||
});
|
||||
}
|
|
@ -9,16 +9,18 @@
|
|||
|
||||
<div class="row">
|
||||
<div class="col-md-3 col-sm-3" id="setup-sidebar-col">
|
||||
<div id="setup-sidebar" class="hidden-xs" data-spy="affix" data-offset-top="55" data-clampedwidth="#setup-sidebar-col">
|
||||
<div id="setup-sidebar" data-clampedwidth="#setup-sidebar-col">
|
||||
<script id="list-group-template" type="text/template">
|
||||
<% _.each(descriptions, function(group){ %>
|
||||
<% panelID = group.name ? group.name : group.html_id %>
|
||||
<li>
|
||||
<a href="#<%- panelID %>" class="list-group-item">
|
||||
<span class="badge"></span>
|
||||
<%- group.label %>
|
||||
</a>
|
||||
</li>
|
||||
<% if (!group.hidden) { %>
|
||||
<% panelID = group.name ? group.name : group.html_id %>
|
||||
<li>
|
||||
<a href="#<%- panelID %>" class="list-group-item">
|
||||
<span class="badge"></span>
|
||||
<%- group.label %>
|
||||
</a>
|
||||
</li>
|
||||
<% } %>
|
||||
<% }); %>
|
||||
</script>
|
||||
|
||||
|
@ -26,49 +28,63 @@
|
|||
</ul>
|
||||
|
||||
<button id="advanced-toggle-button" class="btn btn-info advanced-toggle">Show advanced</button>
|
||||
<button class="btn btn-success save-button">Save</button>
|
||||
<button class="btn btn-success save-button" disabled>Save</button>
|
||||
<div id="manage-cloud-domains-link" style="display: none;">
|
||||
<a href="https://highfidelity.com/user/cloud_domains" target="_blank" class="blue-link">Manage Cloud Hosted Domains</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-9 col-sm-9 col-xs-12">
|
||||
|
||||
<div id="xs-advanced-container" class="col-xs-12 hidden-sm hidden-md hidden-lg">
|
||||
<button id="advanced-toggle-button-xs" class="btn btn-info advanced-toggle">Show advanced</button>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12">
|
||||
|
||||
<div id="cloud-domains-alert" class="alert alert-info alert-dismissible" role="alert" style="display: none;">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<span class="alert-link">
|
||||
<a href="https://highfidelity.com/user/cloud_domains" target="_blank" class="blue-link">Visit Cloud Hosted Domains</a> to manage all your cloud domains
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<form id="settings-form" role="form">
|
||||
|
||||
<script id="panels-template" type="text/template">
|
||||
<% _.each(descriptions, function(group){ %>
|
||||
<% var settings = _.partition(group.settings, function(value, index) { return !value.deprecated })[0] %>
|
||||
<% split_settings = _.partition(settings, function(value, index) { return !value.advanced }) %>
|
||||
<% isAdvanced = _.isEmpty(split_settings[0]) %>
|
||||
<% if (isAdvanced) { %>
|
||||
<% $("a[href=#" + group.name + "]").addClass('advanced-setting').hide() %>
|
||||
<% } %>
|
||||
<% if (!group.hidden) { %>
|
||||
<% var settings = _.partition(group.settings, function(value, index) { return !value.deprecated })[0] %>
|
||||
<% split_settings = _.partition(settings, function(value, index) { return !value.advanced }) %>
|
||||
<% isAdvanced = _.isEmpty(split_settings[0]) && !_.isEmpty(split_settings[1]) %>
|
||||
<% if (isAdvanced) { %>
|
||||
<% $("a[href=#" + group.name + "]").addClass('advanced-setting').hide() %>
|
||||
<% } %>
|
||||
|
||||
<% isGrouped = !!group.name %>
|
||||
<% panelID = isGrouped ? group.name : group.html_id %>
|
||||
<% isGrouped = !!group.name %>
|
||||
<% panelID = isGrouped ? group.name : group.html_id %>
|
||||
|
||||
<div class="panel panel-default<%- (isAdvanced) ? ' advanced-setting' : '' %><%- (isGrouped) ? ' grouped' : '' %>"
|
||||
id="<%- panelID %>">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title"><%- group.label %></h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<% _.each(split_settings[0], function(setting) { %>
|
||||
<% keypath = isGrouped ? group.name + "." + setting.name : setting.name %>
|
||||
<%= getFormGroup(keypath, setting, values, false) %>
|
||||
<% }); %>
|
||||
<% if (!_.isEmpty(split_settings[1])) { %>
|
||||
<% $("#advanced-toggle-button").show() %>
|
||||
<% _.each(split_settings[1], function(setting) { %>
|
||||
<div class="panel panel-default<%- (isAdvanced) ? ' advanced-setting' : '' %><%- (isGrouped) ? ' grouped' : '' %>"
|
||||
id="<%- panelID %>">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title"><%- group.label %></h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<% _.each(split_settings[0], function(setting) { %>
|
||||
<% keypath = isGrouped ? group.name + "." + setting.name : setting.name %>
|
||||
<%= getFormGroup(keypath, setting, values, true) %>
|
||||
<%= getFormGroup(keypath, setting, values, false) %>
|
||||
<% }); %>
|
||||
<% }%>
|
||||
<% if (!_.isEmpty(split_settings[1])) { %>
|
||||
<% $("#advanced-toggle-button").show() %>
|
||||
<% _.each(split_settings[1], function(setting) { %>
|
||||
<% keypath = isGrouped ? group.name + "." + setting.name : setting.name %>
|
||||
<%= getFormGroup(keypath, setting, values, true) %>
|
||||
<% }); %>
|
||||
<% }%>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% } %>
|
||||
<% }); %>
|
||||
</script>
|
||||
<div id="panels"></div>
|
||||
|
@ -85,8 +101,9 @@
|
|||
<script src='/js/underscore-min.js'></script>
|
||||
<script src='/js/underscore-keypath.min.js'></script>
|
||||
<script src='/js/bootbox.min.js'></script>
|
||||
<script src='js/bootstrap-switch.min.js'></script>
|
||||
<script src='js/settings.js'></script>
|
||||
<script src='/js/sha256.js'></script>
|
||||
<script src='js/form2js.min.js'></script>
|
||||
<script src='js/sha256.js'></script>
|
||||
<script src='js/bootstrap-switch.min.js'></script>
|
||||
<script src='/js/shared.js'></script>
|
||||
<script src='js/settings.js'></script>
|
||||
<!--#include virtual="page-end.html"-->
|
||||
|
|
89
domain-server/resources/web/wizard/css/style.css
Normal file
|
@ -0,0 +1,89 @@
|
|||
label {
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
line-height: 24px;
|
||||
font-size: 16px;
|
||||
|
||||
color: #373A3C;
|
||||
}
|
||||
|
||||
.step-title {
|
||||
margin-bottom: 20px;
|
||||
line-height: 26px;
|
||||
font-size: 24px;
|
||||
|
||||
color: #373A3C;
|
||||
}
|
||||
|
||||
.step-description {
|
||||
line-height: 24px;
|
||||
font-size: 16px;
|
||||
|
||||
color: #818A91;
|
||||
}
|
||||
|
||||
.step-info {
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
line-height: 24px;
|
||||
font-size: 16px;
|
||||
|
||||
color: #373A3C;
|
||||
}
|
||||
|
||||
#admin-row {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#connect-question {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#connect-account-btn {
|
||||
margin-top: 30px;
|
||||
margin-bottom: 205px;
|
||||
}
|
||||
|
||||
#place-name-group {
|
||||
margin-top: 42px;
|
||||
margin-bottom: 140px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#place-name-link {
|
||||
line-height: 38px;
|
||||
font-size: 32px;
|
||||
|
||||
display: inline-block;
|
||||
|
||||
color: #373A3C;
|
||||
}
|
||||
|
||||
#place-name-edit {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#change-place-name {
|
||||
line-height: 24px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
#rez-options-row {
|
||||
margin-bottom: 60px;
|
||||
}
|
||||
|
||||
#verify-password-row {
|
||||
margin-bottom: 33px;
|
||||
}
|
||||
|
||||
#checkmark-image {
|
||||
margin-top: 66px;
|
||||
margin-bottom: 59px;
|
||||
width: 169px;
|
||||
height: 169px;
|
||||
}
|
||||
|
||||
#visit-domain-row {
|
||||
margin-bottom: 68px;
|
||||
}
|
29
domain-server/resources/web/wizard/header.html
Normal file
|
@ -0,0 +1,29 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>domain-server</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<link href="/css/bootstrap.min.css" rel="stylesheet" media="screen">
|
||||
<link href="/css/style.css" rel="stylesheet" media="screen">
|
||||
<link href="/wizard/css/style.css" rel="stylesheet" media="screen">
|
||||
<link href="/css/sweetalert.css" rel="stylesheet" media="screen">
|
||||
<link href="/css/bootstrap-switch.min.css" rel="stylesheet" media="screen">
|
||||
|
||||
<script src='/js/sweetalert.min.js'></script>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
|
||||
<div class="container-fluid">
|
||||
<!-- Collect the nav links, forms, and other content for toggling -->
|
||||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
||||
<a class="navbar-brand step-info" href="#">Setup Wizard (Domain Server Settings)</a>
|
||||
|
||||
<div class="navbar-form navbar-right">
|
||||
<button id="skip-wizard-button" type="button" class="btn btn-default" style="display:none;">Skip Wizard</button>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- /.container-fluid -->
|
||||
</nav>
|
||||
|
||||
<div class="container">
|
229
domain-server/resources/web/wizard/index.shtml
Normal file
|
@ -0,0 +1,229 @@
|
|||
<!--#include virtual="wizard/header.html"-->
|
||||
<div class="wizard-step desktop-only col-md-6 col-centered" style="display: none;">
|
||||
<h4 class="step-title"></h4>
|
||||
<dl class="row">
|
||||
<dd class="col-md-12">
|
||||
<span class='step-description'>By connecting your High Fidelity Account you will be granting access to your account information.</span>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="row">
|
||||
<dd class="col-md-12">
|
||||
<a id="connect-account-btn" role="button" class="btn btn-primary btn-md btn-block" target="_blank">Connect your High Fidelity account</a>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl class="row">
|
||||
<dd class="col-md-3">
|
||||
<button type="button" class="btn btn-md btn-block btn-default next-button">Skip</button>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<div class="wizard-step col-md-8 col-centered" style="display: none;">
|
||||
<h4 class="step-title"></h4>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<span class='step-description'>
|
||||
<a target='_blank' href='https://docs.highfidelity.com/create-and-explore/start-working-in-your-sandbox/place-names'>Place names</a> are similar to web addresses. Users who want to visit your domain can
|
||||
enter its Place Name in High Fidelity's Interface. You can choose a Place Name for your domain.</br>
|
||||
People can also use your <b>domain's IP address (shown below)</b> to visit your High Fidelity domain.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="centered-hack-parent">
|
||||
<div id="place-name-group" class="centered-hack">
|
||||
<p id="place-name-link"></p>
|
||||
<div id="place-name-edit">
|
||||
<span class='glyphicon glyphicon-pencil'></span>
|
||||
<a href="#" id="change-place-name">Choose a custom Place Name instead</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<dl class="row">
|
||||
<dd class="col-md-3">
|
||||
<button type="button" class="btn btn-md btn-block btn-default back-button">Back</button>
|
||||
</dd>
|
||||
<dd class="col-md-3 col-md-offset-6">
|
||||
<button type="button" class="btn btn-md btn-block btn-primary next-button">Next</button>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<div class="wizard-step col-md-9 col-centered" style="display: none;">
|
||||
<h4 class="step-title"></h4>
|
||||
<div class="row">
|
||||
<p id="permissions-description" class="col-md-12 step-info"><b>Localhost</b> has been granted administrator privileges to this domain. (Localhost is any</br>user on the same machine as the High Fidelity Server)</p>
|
||||
</div>
|
||||
<div id="admin-row" class="row">
|
||||
<p class="col-md-6">
|
||||
<span id="admin-description" class="step-info"><b>Add your High Fidelity username</b> and any other usernames to grant administrator privileges.</span>
|
||||
<span class='glyphicon glyphicon-info-sign' data-toggle="tooltip" title="Users who will have all the permissions for this domain."></span>
|
||||
</p>
|
||||
<div class="col-md-6">
|
||||
<input id="admin-usernames" type="text" class="form-control">
|
||||
<span class="help-block text-right">separate by commas (user1, user2,..)</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<span class="step-description">Grant basic permissions to other users. You can change these later.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<p id="connect-question" class="step-info">
|
||||
Who can connect to your domain?
|
||||
<span class='glyphicon glyphicon-info-sign' data-toggle='tooltip' title='You can set this to allow a user to connect to this domain.'></span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p class="col-md-2">
|
||||
<label>
|
||||
<input id="connect-none" name="connect-radio" type="radio" value="none" checked> None
|
||||
<span class='glyphicon glyphicon-info-sign' data-toggle='tooltip' title='Only the admins of this domain'></span>
|
||||
</label>
|
||||
</p>
|
||||
<p class="col-md-3">
|
||||
<label>
|
||||
<input id="connect-friends" name="connect-radio" type="radio" value="friends"> Friends
|
||||
<span class='glyphicon glyphicon-info-sign' data-toggle='tooltip' title='Users who are your Friends in High Fidelity'></span>
|
||||
</label>
|
||||
</p>
|
||||
<p class="col-md-5">
|
||||
<label>
|
||||
<input id="connect-logged-in" name="connect-radio" type="radio" value="logged-in"> Users logged in to High Fidelity
|
||||
<span class='glyphicon glyphicon-info-sign' data-toggle='tooltip' title='Users who are currently logged into High Fidelity'></span>
|
||||
</label>
|
||||
</p>
|
||||
<p class="col-md-2">
|
||||
<label>
|
||||
<input id="connect-everyone" name="connect-radio" type="radio" value="everyone"> Everyone
|
||||
<span class='glyphicon glyphicon-info-sign' data-toggle='tooltip' title="Users who aren't logged into High Fidelity"></span>
|
||||
</label>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<p class="step-info">
|
||||
Who can rez items in your domain?
|
||||
<span class='glyphicon glyphicon-info-sign' data-toggle='tooltip' title='You can set this to allow a user to create entities in this domain.'></span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="rez-options-row" class="row">
|
||||
<p class="col-md-2">
|
||||
<label>
|
||||
<input id="rez-none" name="rez-radio" type="radio" value="none" checked> None
|
||||
<span class='glyphicon glyphicon-info-sign' data-toggle='tooltip' title='Only the admins of this domain'></span>
|
||||
</label>
|
||||
</p>
|
||||
<p class="col-md-3">
|
||||
<label>
|
||||
<input id="rez-friends" name="rez-radio" type="radio" value="friends"> Friends
|
||||
<span class='glyphicon glyphicon-info-sign' data-toggle='tooltip' title='Users who are your Friends in High Fidelity'></span>
|
||||
</label>
|
||||
</p>
|
||||
<p class="col-md-5">
|
||||
<label>
|
||||
<input id="rez-logged-in" name="rez-radio" type="radio" value="logged-in"> Users logged in to High Fidelity
|
||||
<span class='glyphicon glyphicon-info-sign' data-toggle='tooltip' title='Users who are currently logged into High Fidelity'></span>
|
||||
</label>
|
||||
</p>
|
||||
<p class="col-md-2">
|
||||
<label>
|
||||
<input id="rez-everyone" name="rez-radio" type="radio" value="everyone"> Everyone
|
||||
<span class='glyphicon glyphicon-info-sign' data-toggle='tooltip' title="Users who aren't logged into High Fidelity"></span>
|
||||
</label>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-3 col-md-offset-9">
|
||||
<button id="save-permissions" type="button" class="btn btn-md btn-block btn-primary">Next</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wizard-step cloud-only col-md-7 col-centered" style="display: none;">
|
||||
<h4 class="step-title"></h4>
|
||||
<dl class="row">
|
||||
<dd class="col-md-12">
|
||||
<span class='step-description'>
|
||||
Your server settings are currently accessible without a username and password.
|
||||
Adding credentials will ensure that only authorized users have access to modify the settings.
|
||||
</span>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<div class="row">
|
||||
<p class="col-md-12 step-info">Create a username and password to secure the access to your domain server settings.</p>
|
||||
</div>
|
||||
<dl class="row">
|
||||
<dt class="col-md-4 step-info">Username</dt>
|
||||
<dd class="col-md-8">
|
||||
<input id="http_username" type="text" class="form-control">
|
||||
<span class='help-block'>This does not have to be your High Fidelity username</span>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="row">
|
||||
<dt class="col-md-4 step-info">Enter password</dt>
|
||||
<dd class="col-md-8">
|
||||
<input id="http_password" type="password" class="form-control">
|
||||
<span class='help-block'>This should not be the same as your High Fidelity password</span>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl id="verify-password-row" class="row">
|
||||
<dt class="col-md-4 step-info">Re-enter password</dt>
|
||||
<dd class="col-md-8">
|
||||
<input id="verify_http_password" type="password" class="form-control">
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl class="row">
|
||||
<dd class="col-md-3 col-md-offset-9">
|
||||
<button id="save-username-password" type="button" class="btn btn-md btn-block btn-primary">Finish</button>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<div class="wizard-step cloud-only col-md-7 col-centered" style="display: none;">
|
||||
<div class="row">
|
||||
<div class="col-xs-4 col-centered">
|
||||
<img id="checkmark-image" src="../images/checkmark.svg">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<p class="step-info">Congratulations! You have successfully setup and configured your cloud hosted domain.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="visit-domain-row" class="row">
|
||||
<div class="col-md-12">
|
||||
<label><input id="go-to-domain" class="form-check-input" type="checkbox"> Visit domain in VR now</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<dl class="row">
|
||||
<dd class="col-md-5 col-md-offset-7">
|
||||
<button id="explore-settings" type="button" class="btn btn-md btn-block btn-primary">Explore all domain server settings</button>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<!--#include virtual="footer.html"-->
|
||||
<script src='/js/underscore-min.js'></script>
|
||||
<script src='/js/bootbox.min.js'></script>
|
||||
<script src='/js/sha256.js'></script>
|
||||
<script src='/js/shared.js'></script>
|
||||
<script src='js/wizard.js'></script>
|
||||
<!--#include virtual="page-end.html"-->
|
471
domain-server/resources/web/wizard/js/wizard.js
Normal file
|
@ -0,0 +1,471 @@
|
|||
var Metaverse = {
|
||||
accessToken: null
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
Strings.ADD_PLACE_NOT_CONNECTED_MESSAGE = "You must have an access token to query your High Fidelity places.<br><br>" +
|
||||
"Please go back and connect your account.";
|
||||
|
||||
$('#connect-account-btn').attr('href', URLs.METAVERSE_URL + "/user/tokens/new?for_domain_server=true");
|
||||
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
|
||||
$('body').on('click', '.next-button', function() {
|
||||
goToNextStep();
|
||||
});
|
||||
|
||||
$('body').on('click', '.back-button', function() {
|
||||
goToPreviousStep();
|
||||
});
|
||||
|
||||
$('body').on('click', '#skip-wizard-button', function() {
|
||||
skipWizard();
|
||||
})
|
||||
|
||||
$('body').on('click', '#connect-account-btn', function() {
|
||||
$(this).blur();
|
||||
prepareAccessTokenPrompt(function(accessToken) {
|
||||
Metaverse.accessToken = accessToken;
|
||||
saveAccessToken();
|
||||
});
|
||||
});
|
||||
|
||||
$('body').on('click', '#save-permissions', function() {
|
||||
savePermissions();
|
||||
});
|
||||
|
||||
function triggerSaveUsernamePassword(event) {
|
||||
if (event.keyCode === 13) {
|
||||
$("#save-username-password").click();
|
||||
}
|
||||
}
|
||||
$("#http_username").keyup(triggerSaveUsernamePassword);
|
||||
$("#http_password").keyup(triggerSaveUsernamePassword);
|
||||
$("#verify_http_password").keyup(triggerSaveUsernamePassword);
|
||||
$('body').on('click', '#save-username-password', function() {
|
||||
saveUsernamePassword();
|
||||
});
|
||||
|
||||
$('body').on('click', '#change-place-name', function() {
|
||||
chooseFromHighFidelityPlaces(Settings.data.values.metaverse.access_token, "/0,-10,0", function(placeName) {
|
||||
updatePlaceNameLink(placeName);
|
||||
});
|
||||
});
|
||||
|
||||
$('body').on('click', '#explore-settings', function() {
|
||||
exploreSettings();
|
||||
});
|
||||
|
||||
reloadSettings(function(success) {
|
||||
if (success) {
|
||||
setupWizardSteps();
|
||||
updatePlaceNameDisplay();
|
||||
updateUsernameDisplay();
|
||||
} else {
|
||||
swal({
|
||||
title: '',
|
||||
type: 'error',
|
||||
text: "There was a problem loading the domain settings.\nPlease refresh the page to try again.",
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function setupWizardSteps() {
|
||||
var stepsCompleted = Settings.data.values.wizard.steps_completed;
|
||||
var steps = null;
|
||||
|
||||
if (Settings.data.values.wizard.cloud_domain) {
|
||||
$('.desktop-only').remove();
|
||||
$('.wizard-step').find('.back-button').hide();
|
||||
|
||||
steps = $('.wizard-step');
|
||||
$(steps).each(function(i) {
|
||||
$(this).children(".step-title").text("Step " + (i + 1) + " of " + (steps.length - 1));
|
||||
});
|
||||
|
||||
$('#permissions-description').html('You <span id="username-display"></span>have been assigned administrator privileges to this domain.');
|
||||
$('#admin-description').html('Add more High Fidelity usernames to grant administrator privileges.');
|
||||
} else {
|
||||
$('.cloud-only').remove();
|
||||
$('#save-permissions').text("Finish");
|
||||
|
||||
steps = $('.wizard-step');
|
||||
$(steps).each(function(i) {
|
||||
$(this).children(".step-title").text("Step " + (i + 1) + " of " + steps.length);
|
||||
});
|
||||
|
||||
if (stepsCompleted == 0) {
|
||||
$('#skip-wizard-button').show();
|
||||
}
|
||||
}
|
||||
|
||||
var currentStep = steps[stepsCompleted];
|
||||
$(currentStep).show();
|
||||
}
|
||||
|
||||
function updatePlaceNameLink(address) {
|
||||
if (address) {
|
||||
$('#place-name-link').html('Your domain is reachable at: <a target="_blank" href="' + URLs.PLACE_URL + '/' + address + '">' + address + '</a>');
|
||||
}
|
||||
}
|
||||
|
||||
function updatePlaceNameDisplay() {
|
||||
if (Settings.data.values.metaverse.id) {
|
||||
$.getJSON(URLs.METAVERSE_URL + '/api/v1/domains/' + Settings.data.values.metaverse.id, function(data) {
|
||||
|
||||
if (data.status === 'success') {
|
||||
if (data.domain.default_place_name) {
|
||||
// Place name
|
||||
updatePlaceNameLink(data.domain.default_place_name);
|
||||
} else if (data.domain.name) {
|
||||
// Temporary name
|
||||
updatePlaceNameLink(data.domain.name);
|
||||
} else if (data.domain.network_address) {
|
||||
if (data.domain.network_port !== 40102) {
|
||||
// IP:PORT
|
||||
updatePlaceNameLink(data.domain.network_address + ':' + data.domain.network_port);
|
||||
} else {
|
||||
// IP
|
||||
updatePlaceNameLink(data.domain.network_address);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.warn('Request Failed');
|
||||
}
|
||||
}).fail(function() {
|
||||
console.warn('Request Failed');
|
||||
});
|
||||
} else {
|
||||
console.warn('No metaverse domain ID!');
|
||||
}
|
||||
}
|
||||
|
||||
function updateUsernameDisplay() {
|
||||
var permissions = Settings.data.values.security.permissions;
|
||||
if (permissions.length > 0) {
|
||||
$('#username-display').html('<b>(' + permissions[0].permissions_id + ')</b> ');
|
||||
}
|
||||
}
|
||||
|
||||
function reloadSettings(callback) {
|
||||
$.getJSON('/settings.json', function(data){
|
||||
Settings.data = data;
|
||||
|
||||
if (callback) {
|
||||
// call the callback now that settings are loaded
|
||||
callback(true);
|
||||
}
|
||||
}).fail(function() {
|
||||
if (callback) {
|
||||
// call the failure object since settings load failed
|
||||
callback(false)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function postSettings(jsonSettings, callback) {
|
||||
console.log("----- SAVING ------");
|
||||
console.log(JSON.stringify(jsonSettings));
|
||||
|
||||
// POST the form JSON to the domain-server settings.json endpoint so the settings are saved
|
||||
$.ajax('/settings.json', {
|
||||
data: JSON.stringify(jsonSettings),
|
||||
contentType: 'application/json',
|
||||
type: 'POST'
|
||||
}).done(function(data){
|
||||
if (data.status == "success") {
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
reloadSettings();
|
||||
} else {
|
||||
swal("Error", Strings.LOADING_SETTINGS_ERROR)
|
||||
reloadSettings();
|
||||
}
|
||||
}).fail(function(){
|
||||
swal("Error", Strings.LOADING_SETTINGS_ERROR)
|
||||
reloadSettings();
|
||||
});
|
||||
}
|
||||
|
||||
function goToNextStep() {
|
||||
$('#skip-wizard-button').hide();
|
||||
|
||||
var currentStep = $('body').find('.wizard-step:visible');
|
||||
var nextStep = currentStep.next('.wizard-step');
|
||||
|
||||
var formJSON = {
|
||||
"wizard": {}
|
||||
}
|
||||
|
||||
if (nextStep.length > 0) {
|
||||
currentStep.hide();
|
||||
nextStep.show();
|
||||
|
||||
var currentStepNumber = parseInt(Settings.data.values.wizard.steps_completed) + 1;
|
||||
|
||||
postSettings({
|
||||
"wizard": {
|
||||
"steps_completed": currentStepNumber.toString()
|
||||
}
|
||||
});
|
||||
} else {
|
||||
postSettings({
|
||||
"wizard": {
|
||||
"steps_completed": "0",
|
||||
"completed_once": true
|
||||
}
|
||||
}, redirectToSettings);
|
||||
}
|
||||
}
|
||||
|
||||
function goToPreviousStep() {
|
||||
var currentStep = $('body').find('.wizard-step:visible');
|
||||
var previousStep = currentStep.prev('.wizard-step');
|
||||
|
||||
var formJSON = {
|
||||
"wizard": {}
|
||||
}
|
||||
|
||||
if (previousStep.length > 0) {
|
||||
currentStep.hide();
|
||||
previousStep.show();
|
||||
|
||||
var currentStepNumber = parseInt(Settings.data.values.wizard.steps_completed) - 1;
|
||||
|
||||
postSettings({
|
||||
"wizard": {
|
||||
"steps_completed": currentStepNumber.toString()
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function skipWizard() {
|
||||
postSettings({
|
||||
"wizard": {
|
||||
"steps_completed": "0",
|
||||
"completed_once": true
|
||||
}
|
||||
}, redirectToSettings);
|
||||
}
|
||||
|
||||
function redirectToSettings() {
|
||||
var redirectURL = "/settings" + location.search;
|
||||
if (Settings.data.values.wizard.cloud_domain) {
|
||||
if (location.search.length > 0) {
|
||||
redirectURL += "&";
|
||||
} else {
|
||||
redirectURL += "?";
|
||||
}
|
||||
redirectURL += "cloud-wizard-exit";
|
||||
}
|
||||
location.href = redirectURL;
|
||||
}
|
||||
|
||||
function saveAccessToken() {
|
||||
var formJSON = {
|
||||
"metaverse": {}
|
||||
}
|
||||
if (Metaverse.accessToken) {
|
||||
formJSON.metaverse.access_token = Metaverse.accessToken;
|
||||
}
|
||||
|
||||
// remove focus from the button
|
||||
$(this).blur();
|
||||
|
||||
// POST the form JSON to the domain-server settings.json endpoint so the settings are saved
|
||||
postSettings(formJSON, goToNextStep);
|
||||
}
|
||||
|
||||
function getSettingDescriptionForKey(groupKey, settingKey) {
|
||||
for (var i in Settings.data.descriptions) {
|
||||
var group = Settings.data.descriptions[i];
|
||||
if (group.name === groupKey) {
|
||||
for (var j in group.settings) {
|
||||
var setting = group.settings[j];
|
||||
if (setting.name === settingKey) {
|
||||
return setting;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function savePermissions() {
|
||||
var localhostPermissions = (Settings.data.values.wizard.cloud_domain !== true)
|
||||
var anonymousCanConnect = false;
|
||||
var friendsCanConnect = false;
|
||||
var loggedInCanConnect = false;
|
||||
var anonymousCanRez = false;
|
||||
var friendsCanRez = false;
|
||||
var loggedInCanRez = false;
|
||||
|
||||
var connectValue = $('input[name=connect-radio]:checked').val();
|
||||
var rezValue = $('input[name=rez-radio]:checked').val();
|
||||
|
||||
switch (connectValue) {
|
||||
case "friends":
|
||||
friendsCanConnect = true;
|
||||
break;
|
||||
case "logged-in":
|
||||
friendsCanConnect = true;
|
||||
loggedInCanConnect = true;
|
||||
break;
|
||||
case "everyone":
|
||||
anonymousCanConnect = true;
|
||||
friendsCanConnect = true;
|
||||
loggedInCanConnect = true;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (rezValue) {
|
||||
case "friends":
|
||||
friendsCanRez = true;
|
||||
break;
|
||||
case "logged-in":
|
||||
friendsCanRez = true;
|
||||
loggedInCanRez = true;
|
||||
break;
|
||||
case "everyone":
|
||||
anonymousCanRez = true;
|
||||
friendsCanRez = true;
|
||||
loggedInCanRez = true;
|
||||
break;
|
||||
}
|
||||
|
||||
var admins = $('#admin-usernames').val().split(',');
|
||||
|
||||
var existingAdmins = Settings.data.values.security.permissions.map(function(value) {
|
||||
return value.permissions_id;
|
||||
});
|
||||
admins = admins.concat(existingAdmins);
|
||||
|
||||
// Filter out unique values
|
||||
admins = _.uniq(admins.map(function(username) {
|
||||
return username.trim();
|
||||
})).filter(function(username) {
|
||||
return username !== "";
|
||||
});
|
||||
|
||||
var formJSON = {
|
||||
"security": {
|
||||
"standard_permissions": [
|
||||
{
|
||||
"id_can_connect": anonymousCanConnect,
|
||||
"id_can_rez": anonymousCanRez,
|
||||
"id_can_rez_certified": anonymousCanRez,
|
||||
"id_can_rez_tmp": anonymousCanRez,
|
||||
"id_can_rez_tmp_certified": anonymousCanRez,
|
||||
"permissions_id": "anonymous"
|
||||
},
|
||||
{
|
||||
"id_can_connect": friendsCanConnect,
|
||||
"id_can_rez": friendsCanRez,
|
||||
"id_can_rez_certified": friendsCanRez,
|
||||
"id_can_rez_tmp": friendsCanRez,
|
||||
"id_can_rez_tmp_certified": friendsCanRez,
|
||||
"permissions_id": "friends"
|
||||
},
|
||||
{
|
||||
"id_can_connect": loggedInCanConnect,
|
||||
"id_can_rez": loggedInCanRez,
|
||||
"id_can_rez_certified": loggedInCanRez,
|
||||
"id_can_rez_tmp": loggedInCanRez,
|
||||
"id_can_rez_tmp_certified": loggedInCanRez,
|
||||
"permissions_id": "logged-in"
|
||||
},
|
||||
{
|
||||
"id_can_adjust_locks": localhostPermissions,
|
||||
"id_can_connect": localhostPermissions,
|
||||
"id_can_connect_past_max_capacity": localhostPermissions,
|
||||
"id_can_kick": localhostPermissions,
|
||||
"id_can_replace_content": localhostPermissions,
|
||||
"id_can_rez": localhostPermissions,
|
||||
"id_can_rez_certified": localhostPermissions,
|
||||
"id_can_rez_tmp": localhostPermissions,
|
||||
"id_can_rez_tmp_certified": localhostPermissions,
|
||||
"id_can_write_to_asset_server": localhostPermissions,
|
||||
"permissions_id": "localhost"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
if (admins.length > 0) {
|
||||
formJSON.security.permissions = [];
|
||||
|
||||
var permissionsDesc = getSettingDescriptionForKey("security", "permissions");
|
||||
for (var i in admins) {
|
||||
var admin = admins[i];
|
||||
var perms = {};
|
||||
for (var i in permissionsDesc.columns) {
|
||||
var name = permissionsDesc.columns[i].name;
|
||||
if (name === "permissions_id") {
|
||||
perms[name] = admin;
|
||||
} else {
|
||||
perms[name] = true;
|
||||
}
|
||||
}
|
||||
formJSON.security.permissions.push(perms);
|
||||
}
|
||||
}
|
||||
|
||||
// remove focus from the button
|
||||
$(this).blur();
|
||||
|
||||
postSettings(formJSON, goToNextStep);
|
||||
}
|
||||
|
||||
function saveUsernamePassword() {
|
||||
var username = $("#http_username").val();
|
||||
var password = $("#http_password").val();
|
||||
var verify_password = $("#verify_http_password").val();
|
||||
|
||||
if (username.length == 0) {
|
||||
bootbox.alert({ "message": "You must set a username!", "title": "Username Error" });
|
||||
return;
|
||||
}
|
||||
|
||||
if (password.length == 0) {
|
||||
bootbox.alert({ "message": "You must set a password!", "title": "Password Error" });
|
||||
return;
|
||||
}
|
||||
|
||||
if (password != verify_password) {
|
||||
bootbox.alert({ "message": "Passwords must match!", "title": "Password Error" });
|
||||
return;
|
||||
}
|
||||
|
||||
var currentStepNumber = parseInt(Settings.data.values.wizard.steps_completed) + 1;
|
||||
|
||||
var formJSON = {
|
||||
"security": {
|
||||
"http_username": username,
|
||||
"http_password": sha256_digest(password)
|
||||
},
|
||||
"wizard": {
|
||||
"steps_completed": currentStepNumber.toString()
|
||||
}
|
||||
}
|
||||
|
||||
// remove focus from the button
|
||||
$(this).blur();
|
||||
|
||||
// POST the form JSON to the domain-server settings.json endpoint so the settings are saved
|
||||
postSettings(formJSON, function() {
|
||||
location.reload();
|
||||
});
|
||||
}
|
||||
|
||||
function exploreSettings() {
|
||||
if ($('#go-to-domain').is(":checked")) {
|
||||
var link = $('#place-name-link a:first');
|
||||
if (link.length > 0) {
|
||||
window.open(link.attr("href"));
|
||||
}
|
||||
}
|
||||
|
||||
goToNextStep();
|
||||
}
|
|
@ -814,9 +814,15 @@ void DomainGatekeeper::processICEPeerInformationPacket(QSharedPointer<ReceivedMe
|
|||
|
||||
void DomainGatekeeper::processICEPingPacket(QSharedPointer<ReceivedMessage> message) {
|
||||
auto limitedNodeList = DependencyManager::get<LimitedNodeList>();
|
||||
auto pingReplyPacket = limitedNodeList->constructICEPingReplyPacket(*message, limitedNodeList->getSessionUUID());
|
||||
|
||||
limitedNodeList->sendPacket(std::move(pingReplyPacket), message->getSenderSockAddr());
|
||||
// before we respond to this ICE ping packet, make sure we have a peer in the list that matches
|
||||
QUuid icePeerID = QUuid::fromRfc4122({ message->getRawMessage(), NUM_BYTES_RFC4122_UUID });
|
||||
|
||||
if (_icePeers.contains(icePeerID)) {
|
||||
auto pingReplyPacket = limitedNodeList->constructICEPingReplyPacket(*message, limitedNodeList->getSessionUUID());
|
||||
|
||||
limitedNodeList->sendPacket(std::move(pingReplyPacket), message->getSenderSockAddr());
|
||||
}
|
||||
}
|
||||
|
||||
void DomainGatekeeper::processICEPingReplyPacket(QSharedPointer<ReceivedMessage> message) {
|
||||
|
|
|
@ -46,6 +46,8 @@
|
|||
#include "DomainServerNodeData.h"
|
||||
#include "NodeConnectionData.h"
|
||||
|
||||
const QString ACCESS_TOKEN_KEY_PATH = "metaverse.access_token";
|
||||
|
||||
int const DomainServer::EXIT_CODE_REBOOT = 234923;
|
||||
|
||||
#if USE_STABLE_GLOBAL_SERVICES
|
||||
|
@ -54,6 +56,82 @@ const QString ICE_SERVER_DEFAULT_HOSTNAME = "ice.highfidelity.com";
|
|||
const QString ICE_SERVER_DEFAULT_HOSTNAME = "dev-ice.highfidelity.com";
|
||||
#endif
|
||||
|
||||
bool DomainServer::forwardMetaverseAPIRequest(HTTPConnection* connection,
|
||||
const QString& metaversePath,
|
||||
const QString& requestSubobjectKey,
|
||||
std::initializer_list<QString> requiredData,
|
||||
std::initializer_list<QString> optionalData,
|
||||
bool requireAccessToken) {
|
||||
|
||||
auto accessTokenVariant = valueForKeyPath(_settingsManager.getSettingsMap(), ACCESS_TOKEN_KEY_PATH);
|
||||
if (accessTokenVariant == nullptr && requireAccessToken) {
|
||||
connection->respond(HTTPConnection::StatusCode400, "User access token has not been set");
|
||||
return true;
|
||||
}
|
||||
|
||||
QJsonObject subobject;
|
||||
|
||||
auto params = connection->parseUrlEncodedForm();
|
||||
|
||||
for (auto& key : requiredData) {
|
||||
auto it = params.find(key);
|
||||
if (it == params.end()) {
|
||||
auto error = "Bad request, expected param '" + key + "'";
|
||||
connection->respond(HTTPConnection::StatusCode400, error.toLatin1());
|
||||
return true;
|
||||
}
|
||||
subobject.insert(key, it.value());
|
||||
}
|
||||
|
||||
for (auto& key : optionalData) {
|
||||
auto it = params.find(key);
|
||||
if (it != params.end()) {
|
||||
subobject.insert(key, it.value());
|
||||
}
|
||||
}
|
||||
|
||||
QJsonObject root;
|
||||
root.insert(requestSubobjectKey, subobject);
|
||||
QJsonDocument doc { root };
|
||||
|
||||
QUrl url { NetworkingConstants::METAVERSE_SERVER_URL.toString() + metaversePath };
|
||||
|
||||
QNetworkRequest req(url);
|
||||
req.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
req.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
|
||||
if (accessTokenVariant != nullptr) {
|
||||
auto accessTokenHeader = QString("Bearer ") + accessTokenVariant->toString();
|
||||
req.setRawHeader("Authorization", accessTokenHeader.toLatin1());
|
||||
}
|
||||
|
||||
QNetworkReply* reply;
|
||||
auto method = connection->requestOperation();
|
||||
if (method == QNetworkAccessManager::GetOperation) {
|
||||
reply = NetworkAccessManager::getInstance().get(req);
|
||||
} else if (method == QNetworkAccessManager::PostOperation) {
|
||||
reply = NetworkAccessManager::getInstance().post(req, doc.toJson());
|
||||
} else if (method == QNetworkAccessManager::PutOperation) {
|
||||
reply = NetworkAccessManager::getInstance().put(req, doc.toJson());
|
||||
} else {
|
||||
connection->respond(HTTPConnection::StatusCode400, "Error forwarding request, unsupported method");
|
||||
return true;
|
||||
}
|
||||
|
||||
connect(reply, &QNetworkReply::finished, this, [reply, connection]() {
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
auto data = reply->readAll();
|
||||
qDebug() << "Got error response from metaverse server (" << reply->url() << "): " << data << reply->errorString();
|
||||
connection->respond(HTTPConnection::StatusCode400, data);
|
||||
return;
|
||||
}
|
||||
|
||||
connection->respond(HTTPConnection::StatusCode200, reply->readAll());
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
DomainServer::DomainServer(int argc, char* argv[]) :
|
||||
QCoreApplication(argc, argv),
|
||||
_gatekeeper(this),
|
||||
|
@ -614,8 +692,6 @@ void DomainServer::setupNodeListAndAssignments() {
|
|||
nodeList->setPacketFilterOperator(&DomainServer::isPacketVerified);
|
||||
}
|
||||
|
||||
const QString ACCESS_TOKEN_KEY_PATH = "metaverse.access_token";
|
||||
|
||||
bool DomainServer::resetAccountManagerAccessToken() {
|
||||
if (!_oauthProviderURL.isEmpty()) {
|
||||
// check for an access-token in our settings, can optionally be overidden by env value
|
||||
|
@ -754,26 +830,6 @@ void DomainServer::setupICEHeartbeatForFullNetworking() {
|
|||
void DomainServer::updateICEServerAddresses() {
|
||||
if (_iceAddressLookupID == INVALID_ICE_LOOKUP_ID) {
|
||||
_iceAddressLookupID = QHostInfo::lookupHost(_iceServerAddr, this, SLOT(handleICEHostInfo(QHostInfo)));
|
||||
|
||||
// there seems to be a 5.9 bug where lookupHost never calls our slot
|
||||
// so we add a single shot manual "timeout" to fire it off again if it hasn't called back yet
|
||||
static const int ICE_ADDRESS_LOOKUP_TIMEOUT_MS = 5000;
|
||||
QTimer::singleShot(ICE_ADDRESS_LOOKUP_TIMEOUT_MS, this, &DomainServer::timeoutICEAddressLookup);
|
||||
}
|
||||
}
|
||||
|
||||
void DomainServer::timeoutICEAddressLookup() {
|
||||
if (_iceAddressLookupID != INVALID_ICE_LOOKUP_ID) {
|
||||
// we waited 5s and didn't hear back for our ICE DNS lookup
|
||||
// so time that one out and kick off another
|
||||
|
||||
qDebug() << "IP address lookup timed out for" << _iceServerAddr << "- retrying";
|
||||
|
||||
QHostInfo::abortHostLookup(_iceAddressLookupID);
|
||||
|
||||
_iceAddressLookupID = INVALID_ICE_LOOKUP_ID;
|
||||
|
||||
updateICEServerAddresses();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1731,6 +1787,8 @@ QString DomainServer::pathForRedirect(QString path) const {
|
|||
return "http://" + _hostname + ":" + QString::number(_httpManager.serverPort()) + path;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const QString URI_OAUTH = "/oauth";
|
||||
bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler) {
|
||||
const QString JSON_MIME_TYPE = "application/json";
|
||||
|
@ -1740,15 +1798,23 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
const QString URI_SETTINGS = "/settings";
|
||||
const QString URI_ENTITY_FILE_UPLOAD = "/content/upload";
|
||||
const QString URI_RESTART = "/restart";
|
||||
const QString URI_API_PLACES = "/api/places";
|
||||
const QString URI_API_DOMAINS = "/api/domains";
|
||||
const QString URI_API_DOMAINS_ID = "/api/domains/";
|
||||
|
||||
const QString UUID_REGEX_STRING = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
|
||||
|
||||
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
||||
|
||||
// allow sub-handlers to handle requests that do not require authentication
|
||||
if (_settingsManager.handlePublicHTTPRequest(connection, url)) {
|
||||
auto getSetting = [this](QString keyPath, QVariant& value) -> bool {
|
||||
QVariantMap& settingsMap = _settingsManager.getSettingsMap();
|
||||
QVariant* var = valueForKeyPath(settingsMap, keyPath);
|
||||
if (var == nullptr) {
|
||||
return false;
|
||||
}
|
||||
value = *var;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// check if this is a request for a scripted assignment (with a temp unique UUID)
|
||||
const QString ASSIGNMENT_REGEX_STRING = QString("\\%1\\/(%2)\\/?$").arg(URI_ASSIGNMENT).arg(UUID_REGEX_STRING);
|
||||
|
@ -1810,6 +1876,31 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
return true;
|
||||
}
|
||||
|
||||
// Check if we should redirect/prevent access to the wizard
|
||||
if (connection->requestOperation() == QNetworkAccessManager::GetOperation) {
|
||||
const QString URI_WIZARD = "/wizard/";
|
||||
const QString WIZARD_COMPLETED_ONCE_KEY_PATH = "wizard.completed_once";
|
||||
const QVariant* wizardCompletedOnce = valueForKeyPath(_settingsManager.getSettingsMap(), WIZARD_COMPLETED_ONCE_KEY_PATH);
|
||||
const bool completedOnce = wizardCompletedOnce && wizardCompletedOnce->toBool();
|
||||
|
||||
if (url.path() != URI_WIZARD && url.path().endsWith('/') && !completedOnce) {
|
||||
// First visit, redirect to the wizard
|
||||
QUrl redirectedURL = url;
|
||||
redirectedURL.setPath(URI_WIZARD);
|
||||
|
||||
Headers redirectHeaders;
|
||||
redirectHeaders.insert("Location", redirectedURL.toEncoded());
|
||||
|
||||
connection->respond(HTTPConnection::StatusCode302,
|
||||
QByteArray(), HTTPConnection::DefaultContentType, redirectHeaders);
|
||||
return true;
|
||||
} else if (url.path() == URI_WIZARD && completedOnce) {
|
||||
// Wizard already completed, return 404
|
||||
connection->respond(HTTPConnection::StatusCode404, "Resource not found.");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (connection->requestOperation() == QNetworkAccessManager::GetOperation) {
|
||||
if (url.path() == "/assignments.json") {
|
||||
// user is asking for json list of assignments
|
||||
|
@ -1899,6 +1990,13 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
connection->respond(HTTPConnection::StatusCode200);
|
||||
restart();
|
||||
return true;
|
||||
} else if (url.path() == URI_API_DOMAINS) {
|
||||
return forwardMetaverseAPIRequest(connection, "/api/v1/domains", "");
|
||||
} else if (url.path().startsWith(URI_API_DOMAINS_ID)) {
|
||||
auto id = url.path().mid(URI_API_DOMAINS_ID.length());
|
||||
return forwardMetaverseAPIRequest(connection, "/api/v1/domains/" + id, "", {}, {}, false);
|
||||
} else if (url.path() == URI_API_PLACES) {
|
||||
return forwardMetaverseAPIRequest(connection, "/api/v1/user/places", "");
|
||||
} else {
|
||||
// check if this is for json stats for a node
|
||||
const QString NODE_JSON_REGEX_STRING = QString("\\%1\\/(%2).json\\/?$").arg(URI_NODES).arg(UUID_REGEX_STRING);
|
||||
|
@ -1978,8 +2076,6 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
// this is an entity file upload, ask the HTTPConnection to parse the data
|
||||
QList<FormData> formData = connection->parseFormData();
|
||||
|
||||
Headers redirectHeaders;
|
||||
|
||||
if (formData.size() > 0 && formData[0].second.size() > 0) {
|
||||
// invoke our method to hand the new octree file off to the octree server
|
||||
QMetaObject::invokeMethod(this, "handleOctreeFileReplacement",
|
||||
|
@ -1993,7 +2089,98 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
}
|
||||
|
||||
return true;
|
||||
|
||||
} else if (url.path() == "/domain_settings") {
|
||||
auto accessTokenVariant = valueForKeyPath(_settingsManager.getSettingsMap(), ACCESS_TOKEN_KEY_PATH);
|
||||
if (!accessTokenVariant) {
|
||||
connection->respond(HTTPConnection::StatusCode400);
|
||||
return true;
|
||||
}
|
||||
|
||||
} else if (url.path() == URI_API_DOMAINS) {
|
||||
|
||||
return forwardMetaverseAPIRequest(connection, "/api/v1/domains", "domain", { "label" });
|
||||
}
|
||||
} else if (connection->requestOperation() == QNetworkAccessManager::PutOperation) {
|
||||
if (url.path() == URI_API_DOMAINS) {
|
||||
QVariant domainSetting;
|
||||
if (!getSetting(METAVERSE_DOMAIN_ID_KEY_PATH, domainSetting)) {
|
||||
connection->respond(HTTPConnection::StatusCode400, "Domain id has not been set");
|
||||
return true;
|
||||
}
|
||||
auto domainID = domainSetting.toString();
|
||||
return forwardMetaverseAPIRequest(connection, "/api/v1/domains/" + domainID, "domain",
|
||||
{ }, { "network_address", "network_port", "label" });
|
||||
} else if (url.path() == URI_API_PLACES) {
|
||||
auto accessTokenVariant = valueForKeyPath(_settingsManager.getSettingsMap(), ACCESS_TOKEN_KEY_PATH);
|
||||
if (!accessTokenVariant->isValid()) {
|
||||
connection->respond(HTTPConnection::StatusCode400, "User access token has not been set");
|
||||
return true;
|
||||
}
|
||||
|
||||
auto params = connection->parseUrlEncodedForm();
|
||||
|
||||
auto it = params.find("place_id");
|
||||
if (it == params.end()) {
|
||||
connection->respond(HTTPConnection::StatusCode400);
|
||||
return true;
|
||||
}
|
||||
QString place_id = it.value();
|
||||
|
||||
it = params.find("path");
|
||||
if (it == params.end()) {
|
||||
connection->respond(HTTPConnection::StatusCode400);
|
||||
return true;
|
||||
}
|
||||
QString path = it.value();
|
||||
|
||||
it = params.find("domain_id");
|
||||
QString domainID;
|
||||
if (it == params.end()) {
|
||||
QVariant domainSetting;
|
||||
if (!getSetting(METAVERSE_DOMAIN_ID_KEY_PATH, domainSetting)) {
|
||||
connection->respond(HTTPConnection::StatusCode400);
|
||||
return true;
|
||||
}
|
||||
domainID = domainSetting.toString();
|
||||
} else {
|
||||
domainID = it.value();
|
||||
}
|
||||
|
||||
QJsonObject root {
|
||||
{
|
||||
"place",
|
||||
QJsonObject({
|
||||
{ "pointee_query", domainID },
|
||||
{ "path", path }
|
||||
})
|
||||
}
|
||||
};
|
||||
QJsonDocument doc(root);
|
||||
|
||||
|
||||
QUrl url { NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/api/v1/places/" + place_id };
|
||||
|
||||
url.setQuery("access_token=" + accessTokenVariant->toString());
|
||||
|
||||
QNetworkRequest req(url);
|
||||
req.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
req.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
QNetworkReply* reply = NetworkAccessManager::getInstance().put(req, doc.toJson());
|
||||
|
||||
connect(reply, &QNetworkReply::finished, this, [reply, connection]() {
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
qDebug() << "Got error response from metaverse server: " << reply->readAll();
|
||||
connection->respond(HTTPConnection::StatusCode500,
|
||||
"Error communicating with Metaverse");
|
||||
return;
|
||||
}
|
||||
|
||||
connection->respond(HTTPConnection::StatusCode200, reply->readAll());
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
} else if (connection->requestOperation() == QNetworkAccessManager::DeleteOperation) {
|
||||
const QString ALL_NODE_DELETE_REGEX_STRING = QString("\\%1\\/?$").arg(URI_NODES);
|
||||
const QString NODE_DELETE_REGEX_STRING = QString("\\%1\\/(%2)\\/$").arg(URI_NODES).arg(UUID_REGEX_STRING);
|
||||
|
@ -2037,7 +2224,6 @@ static const QString HIFI_SESSION_COOKIE_KEY = "DS_WEB_SESSION_UUID";
|
|||
static const QString STATE_QUERY_KEY = "state";
|
||||
|
||||
bool DomainServer::handleHTTPSRequest(HTTPSConnection* connection, const QUrl &url, bool skipSubHandler) {
|
||||
qDebug() << "HTTPS request received at" << url.toString();
|
||||
if (url.path() == URI_OAUTH) {
|
||||
|
||||
QUrlQuery codeURLQuery(url);
|
||||
|
@ -2298,6 +2484,8 @@ QNetworkReply* DomainServer::profileRequestGivenTokenReply(QNetworkReply* tokenR
|
|||
profileURL.setPath("/api/v1/user/profile");
|
||||
profileURL.setQuery(QString("%1=%2").arg(OAUTH_JSON_ACCESS_TOKEN_KEY, accessToken));
|
||||
|
||||
qDebug() << "Sending profile request to: " << profileURL;
|
||||
|
||||
QNetworkRequest profileRequest(profileURL);
|
||||
profileRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
profileRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
|
@ -2799,9 +2987,20 @@ void DomainServer::handleKeypairChange() {
|
|||
|
||||
void DomainServer::handleICEHostInfo(const QHostInfo& hostInfo) {
|
||||
// clear the ICE address lookup ID so that it can fire again
|
||||
_iceAddressLookupID = -1;
|
||||
_iceAddressLookupID = INVALID_ICE_LOOKUP_ID;
|
||||
|
||||
if (hostInfo.error() != QHostInfo::NoError) {
|
||||
// enumerate the returned addresses and collect only valid IPv4 addresses
|
||||
QList<QHostAddress> sanitizedAddresses = hostInfo.addresses();
|
||||
auto it = sanitizedAddresses.begin();
|
||||
while (it != sanitizedAddresses.end()) {
|
||||
if (!it->isNull() && it->protocol() == QAbstractSocket::IPv4Protocol) {
|
||||
++it;
|
||||
} else {
|
||||
it = sanitizedAddresses.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
if (hostInfo.error() != QHostInfo::NoError || sanitizedAddresses.empty()) {
|
||||
qWarning() << "IP address lookup failed for" << _iceServerAddr << ":" << hostInfo.errorString();
|
||||
|
||||
// if we don't have an ICE server to use yet, trigger a retry
|
||||
|
@ -2814,7 +3013,7 @@ void DomainServer::handleICEHostInfo(const QHostInfo& hostInfo) {
|
|||
} else {
|
||||
int countBefore = _iceServerAddresses.count();
|
||||
|
||||
_iceServerAddresses = hostInfo.addresses();
|
||||
_iceServerAddresses = sanitizedAddresses;
|
||||
|
||||
if (countBefore == 0) {
|
||||
qInfo() << "Found" << _iceServerAddresses.count() << "ice-server IP addresses for" << _iceServerAddr;
|
||||
|
|
|
@ -116,8 +116,6 @@ private slots:
|
|||
void tokenGrantFinished();
|
||||
void profileRequestFinished();
|
||||
|
||||
void timeoutICEAddressLookup();
|
||||
|
||||
signals:
|
||||
void iceServerChanged();
|
||||
void userConnected();
|
||||
|
@ -187,6 +185,13 @@ private:
|
|||
|
||||
HTTPSConnection* connectionFromReplyWithState(QNetworkReply* reply);
|
||||
|
||||
bool forwardMetaverseAPIRequest(HTTPConnection* connection,
|
||||
const QString& metaversePath,
|
||||
const QString& requestSubobject,
|
||||
std::initializer_list<QString> requiredData = { },
|
||||
std::initializer_list<QString> optionalData = { },
|
||||
bool requireAccessToken = true);
|
||||
|
||||
SubnetList _acSubnetWhitelist;
|
||||
|
||||
std::vector<QString> _replicatedUsernames;
|
||||
|
|
|
@ -310,6 +310,16 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList
|
|||
_standardAgentPermissions[NodePermissions::standardNameLocalhost]->set(NodePermissions::Permission::canRezTemporaryCertifiedEntities);
|
||||
packPermissions();
|
||||
}
|
||||
if (oldVersion < 2.0) {
|
||||
const QString WIZARD_COMPLETED_ONCE = "wizard.completed_once";
|
||||
|
||||
QVariant* wizardCompletedOnce = _configMap.valueForKeyPath(WIZARD_COMPLETED_ONCE, true);
|
||||
|
||||
*wizardCompletedOnce = QVariant(true);
|
||||
|
||||
// write the new settings to the json file
|
||||
persistToFile();
|
||||
}
|
||||
}
|
||||
|
||||
unpackPermissions();
|
||||
|
@ -960,29 +970,6 @@ QVariant DomainServerSettingsManager::valueOrDefaultValueForKeyPath(const QStrin
|
|||
return QVariant();
|
||||
}
|
||||
|
||||
bool DomainServerSettingsManager::handlePublicHTTPRequest(HTTPConnection* connection, const QUrl &url) {
|
||||
if (connection->requestOperation() == QNetworkAccessManager::GetOperation && url.path() == SETTINGS_PATH_JSON) {
|
||||
// this is a GET operation for our settings
|
||||
|
||||
// check if there is a query parameter for settings affecting a particular type of assignment
|
||||
const QString SETTINGS_TYPE_QUERY_KEY = "type";
|
||||
QUrlQuery settingsQuery(url);
|
||||
QString typeValue = settingsQuery.queryItemValue(SETTINGS_TYPE_QUERY_KEY);
|
||||
|
||||
if (!typeValue.isEmpty()) {
|
||||
QJsonObject responseObject = responseObjectForType(typeValue);
|
||||
|
||||
connection->respond(HTTPConnection::StatusCode200, QJsonDocument(responseObject).toJson(), "application/json");
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DomainServerSettingsManager::handleAuthenticatedHTTPRequest(HTTPConnection *connection, const QUrl &url) {
|
||||
if (connection->requestOperation() == QNetworkAccessManager::PostOperation && url.path() == SETTINGS_PATH_JSON) {
|
||||
// this is a POST operation to change one or more settings
|
||||
|
@ -1214,6 +1201,7 @@ bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ
|
|||
static const QString SECURITY_ROOT_KEY = "security";
|
||||
static const QString AC_SUBNET_WHITELIST_KEY = "ac_subnet_whitelist";
|
||||
static const QString BROADCASTING_KEY = "broadcasting";
|
||||
static const QString WIZARD_KEY = "wizard";
|
||||
static const QString DESCRIPTION_ROOT_KEY = "descriptors";
|
||||
|
||||
auto& settingsVariant = _configMap.getConfig();
|
||||
|
@ -1266,7 +1254,8 @@ bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ
|
|||
|
||||
if (!matchingDescriptionObject.isEmpty()) {
|
||||
updateSetting(rootKey, rootValue, *thisMap, matchingDescriptionObject);
|
||||
if (rootKey != SECURITY_ROOT_KEY && rootKey != BROADCASTING_KEY && rootKey != SETTINGS_PATHS_KEY ) {
|
||||
if (rootKey != SECURITY_ROOT_KEY && rootKey != BROADCASTING_KEY &&
|
||||
rootKey != SETTINGS_PATHS_KEY && rootKey != WIZARD_KEY) {
|
||||
needRestart = true;
|
||||
}
|
||||
} else {
|
||||
|
@ -1282,8 +1271,9 @@ bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ
|
|||
if (!matchingDescriptionObject.isEmpty()) {
|
||||
const QJsonValue& settingValue = rootValue.toObject()[settingKey];
|
||||
updateSetting(settingKey, settingValue, *thisMap, matchingDescriptionObject);
|
||||
if ((rootKey != SECURITY_ROOT_KEY && rootKey != BROADCASTING_KEY && rootKey != DESCRIPTION_ROOT_KEY)
|
||||
|| settingKey == AC_SUBNET_WHITELIST_KEY) {
|
||||
if ((rootKey != SECURITY_ROOT_KEY && rootKey != BROADCASTING_KEY &&
|
||||
rootKey != DESCRIPTION_ROOT_KEY && rootKey != WIZARD_KEY) ||
|
||||
settingKey == AC_SUBNET_WHITELIST_KEY) {
|
||||
needRestart = true;
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -43,7 +43,6 @@ class DomainServerSettingsManager : public QObject {
|
|||
Q_OBJECT
|
||||
public:
|
||||
DomainServerSettingsManager();
|
||||
bool handlePublicHTTPRequest(HTTPConnection* connection, const QUrl& url);
|
||||
bool handleAuthenticatedHTTPRequest(HTTPConnection* connection, const QUrl& url);
|
||||
|
||||
void setupConfigMap(const QStringList& argumentList);
|
||||
|
|
|
@ -1,6 +1,20 @@
|
|||
set(TARGET_NAME interface)
|
||||
project(${TARGET_NAME})
|
||||
|
||||
file(GLOB_RECURSE QML_SRC resources/qml/*.qml resources/qml/*.js)
|
||||
add_custom_target(qml SOURCES ${QML_SRC})
|
||||
GroupSources("resources/qml")
|
||||
|
||||
function(JOIN VALUES GLUE OUTPUT)
|
||||
string (REGEX REPLACE "([^\\]|^);" "\\1${GLUE}" _TMP_STR "${VALUES}")
|
||||
string (REGEX REPLACE "[\\](.)" "\\1" _TMP_STR "${_TMP_STR}") #fixes escaping
|
||||
set (${OUTPUT} "${_TMP_STR}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
set(INTERFACE_QML_QRC ${CMAKE_CURRENT_BINARY_DIR}/qml.qrc)
|
||||
generate_qrc(OUTPUT ${INTERFACE_QML_QRC} PATH ${CMAKE_CURRENT_SOURCE_DIR}/resources GLOBS *.qml *.qss *.js *.html *.ttf *.gif *.svg *.png *.jpg)
|
||||
|
||||
# set a default root dir for each of our optional externals if it was not passed
|
||||
set(OPTIONAL_EXTERNALS "LeapMotion")
|
||||
|
||||
|
@ -66,9 +80,7 @@ qt5_wrap_ui(QT_UI_HEADERS "${QT_UI_FILES}")
|
|||
# add them to the interface source files
|
||||
set(INTERFACE_SRCS ${INTERFACE_SRCS} "${QT_UI_HEADERS}" "${QT_RESOURCES}")
|
||||
|
||||
file(GLOB_RECURSE QML_SRC resources/qml/*.qml resources/qml/*.js)
|
||||
add_custom_target(qml SOURCES ${QML_SRC})
|
||||
GroupSources("resources/qml")
|
||||
list(APPEND INTERFACE_SRCS ${INTERFACE_QML_QRC})
|
||||
|
||||
if (UNIX)
|
||||
install(
|
||||
|
@ -131,10 +143,10 @@ if (APPLE)
|
|||
|
||||
# append the discovered resources to our list of interface sources
|
||||
list(APPEND INTERFACE_SRCS ${DISCOVERED_RESOURCES})
|
||||
|
||||
set(INTERFACE_SRCS ${INTERFACE_SRCS} "${CMAKE_CURRENT_SOURCE_DIR}/icon/${INTERFACE_ICON_FILENAME}")
|
||||
list(APPEND INTERFACE_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/icon/${INTERFACE_ICON_FILENAME})
|
||||
endif()
|
||||
|
||||
|
||||
# create the executable, make it a bundle on OS X
|
||||
if (APPLE)
|
||||
add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS} ${QM})
|
||||
|
@ -198,6 +210,7 @@ endif()
|
|||
# link required hifi libraries
|
||||
link_hifi_libraries(
|
||||
shared octree ktx gpu gl gpu-gl procedural model render
|
||||
pointers
|
||||
recording fbx networking model-networking entities avatars trackers
|
||||
audio audio-client animation script-engine physics
|
||||
render-utils entities-renderer avatars-renderer ui auto-updater midi
|
||||
|
@ -262,7 +275,13 @@ target_link_libraries(
|
|||
)
|
||||
|
||||
if (UNIX)
|
||||
target_link_libraries(${TARGET_NAME} pthread)
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
# Linux
|
||||
target_link_libraries(${TARGET_NAME} pthread atomic)
|
||||
else ()
|
||||
# OSX
|
||||
target_link_libraries(${TARGET_NAME} pthread)
|
||||
endif ()
|
||||
endif(UNIX)
|
||||
|
||||
# assume we are using a Qt build without bearer management
|
||||
|
|
609
interface/resources/html/commerce/backup_instructions.html
Normal file
|
@ -0,0 +1,609 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<style>
|
||||
|
||||
body
|
||||
{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: #333;
|
||||
background-color: #eee;
|
||||
font: 300 16px/22px "Lato", "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
background: rgba(74,219,255,1);
|
||||
background: -moz-linear-gradient(-45deg, rgba(74,219,255,1) 0%, rgba(61,171,255,1) 41%, rgba(54,124,209,1) 100%);
|
||||
background: -webkit-gradient(left top, right bottom, color-stop(0%, rgba(74,219,255,1)), color-stop(41%, rgba(61,171,255,1)), color-stop(100%, rgba(54,124,209,1)));
|
||||
background: -webkit-linear-gradient(-45deg, rgba(74,219,255,1) 0%, rgba(61,171,255,1) 41%, rgba(54,124,209,1) 100%);
|
||||
background: -o-linear-gradient(-45deg, rgba(74,219,255,1) 0%, rgba(61,171,255,1) 41%, rgba(54,124,209,1) 100%);
|
||||
background: -ms-linear-gradient(-45deg, rgba(74,219,255,1) 0%, rgba(61,171,255,1) 41%, rgba(54,124,209,1) 100%);
|
||||
background: linear-gradient(135deg, rgba(74,219,255,1) 0%, rgba(61,171,255,1) 41%, rgba(54,124,209,1) 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#4adbff', endColorstr='#367cd1', GradientType=1 );
|
||||
}
|
||||
|
||||
h1,h2,h3,h4,h5,h6
|
||||
{
|
||||
margin: 0 0 .5em;
|
||||
font-weight: 500;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
h1 { font-size: 2.25em; } /* 36px */
|
||||
h2 { font-size: 1.75em; } /* 28px */
|
||||
h3 { font-size: 1.375em; } /* 22px */
|
||||
h4 { font-size: 1.125em; } /* 18px */
|
||||
h5 { font-size: 1em; } /* 16px */
|
||||
h6 { font-size: .875em; } /* 14px */
|
||||
|
||||
p
|
||||
{
|
||||
margin: 0 0 1.5em;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
blockquote
|
||||
{
|
||||
padding: 1em 2em;
|
||||
margin: 0 0 2em;
|
||||
border-left: 5px solid #eee;
|
||||
}
|
||||
|
||||
hr
|
||||
{
|
||||
height: 0;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 2em;
|
||||
border: 0;
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
|
||||
table
|
||||
{
|
||||
background-color: transparent;
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
|
||||
th, td
|
||||
{
|
||||
padding: .5em 1em;
|
||||
vertical-align: top;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
a:link { color: #0093C5; }
|
||||
a:visited { color: #0093C5; }
|
||||
a:focus { color: black; }
|
||||
a:hover { color: #00B4EF; }
|
||||
a:active { color: #00B4EF; }
|
||||
|
||||
/* -----------------------
|
||||
Layout styles
|
||||
------------------------*/
|
||||
|
||||
.container
|
||||
{
|
||||
max-width: 50em;
|
||||
margin: 0 auto;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.header
|
||||
{
|
||||
color: #fff;
|
||||
background: #333;
|
||||
padding: 1em 1.25em;
|
||||
}
|
||||
|
||||
.header-heading { margin: 0; }
|
||||
|
||||
.nav-bar
|
||||
{
|
||||
background: #000;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.content { padding: 1em 1.25em; }
|
||||
|
||||
.footer
|
||||
{
|
||||
color: #fff;
|
||||
background: #000;
|
||||
|
||||
}
|
||||
|
||||
.alert
|
||||
{
|
||||
padding: 1em 1.25em;
|
||||
border-radius: 2px;
|
||||
border-width: thin;
|
||||
border-color: #ccc;
|
||||
background: #eee;
|
||||
}
|
||||
/* -----------------------
|
||||
Nav
|
||||
------------------------*/
|
||||
|
||||
.nav
|
||||
{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.nav li
|
||||
{
|
||||
display: inline;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.nav a
|
||||
{
|
||||
display: block;
|
||||
padding: .7em 1.25em;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
border-bottom: 1px solid gray;
|
||||
}
|
||||
|
||||
.nav a:link { color: white; }
|
||||
.nav a:visited { color: white; }
|
||||
|
||||
.nav a:focus
|
||||
{
|
||||
color: black;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.nav a:hover
|
||||
{
|
||||
color: white;
|
||||
background-color: green;
|
||||
}
|
||||
|
||||
.nav a:active
|
||||
{
|
||||
color: white;
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
/* -----------------------
|
||||
Single styles
|
||||
------------------------*/
|
||||
|
||||
.img-responsive { max-width: 100%; }
|
||||
|
||||
.btn
|
||||
{
|
||||
color: #fff !important;
|
||||
background-color: royalblue;
|
||||
border-color: #222;
|
||||
display: inline-block;
|
||||
padding: .5em 1em;
|
||||
margin-bottom: 0;
|
||||
font-weight: 400;
|
||||
line-height: 1.2;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
border: 1px solid transparent;
|
||||
border-radius: .2em;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.btn:hover
|
||||
{
|
||||
color: #fff !important;
|
||||
background-color: #0093C5;
|
||||
}
|
||||
|
||||
.btn:focus
|
||||
{
|
||||
color: #fff !important;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.btn:active
|
||||
{
|
||||
color: #fff !important;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.table
|
||||
{
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.list-unstyled
|
||||
{
|
||||
padding-left: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.list-inline
|
||||
{
|
||||
padding-left: 0;
|
||||
margin-left: -5px;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.list-inline > li
|
||||
{
|
||||
display: inline-block;
|
||||
padding-right: 5px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* -----------------------
|
||||
Wide styles
|
||||
------------------------*/
|
||||
|
||||
@media (min-width: 42em)
|
||||
{
|
||||
.header { padding: 1.5em 3em; }
|
||||
.nav-bar { padding: 1em 3em; }
|
||||
.content { padding: 2em 3em; }
|
||||
.footer { padding: 2em 3em; }
|
||||
|
||||
.nav li
|
||||
{
|
||||
display: inline;
|
||||
margin: 0 1em 0 0;
|
||||
}
|
||||
|
||||
.nav a
|
||||
{
|
||||
display: inline;
|
||||
padding: 0;
|
||||
border-bottom: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<title>Backing Up Your Private Keys | High Fidelity</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 1200 95" style="enable-background:new 0 0 1200 95;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st15{fill:#10bcff;}
|
||||
.st16{fill:#939598;}
|
||||
</style>
|
||||
<g id="Layer_1_1_">
|
||||
<path class="st15" d="M144,35.8v29.2h-6.3V52.3h-10.3v12.8h-6.3V35.8h6.3v11.3h10.3V35.8H144z"/>
|
||||
<path class="st15" d="M155.1,65.1h-6.3V35.8h6.3V65.1z"/>
|
||||
<path class="st15" d="M173.2,40.5c-1.5,0-2.7,0.1-3.8,0.4c-1,0.3-1.8,0.8-2.5,1.4c-0.6,0.6-1.1,1.6-1.4,2.7s-0.4,2.5-0.4,4.2v2.7
|
||||
c0,1.8,0.1,3.2,0.4,4.3c0.2,1.1,0.6,2,1.2,2.6c0.5,0.6,1.3,1.1,2.2,1.3c0.9,0.2,2,0.4,3.3,0.4c0.4,0,0.8,0,1.2-0.1
|
||||
c0.4,0,0.8-0.1,1.3-0.1v-7.9h-3.7l0.6-4.8h9v16.7c-1.1,0.4-2.5,0.7-4.3,0.9c-1.7,0.2-3.4,0.4-5.2,0.4c-2.2,0-4.1-0.3-5.7-0.8
|
||||
c-1.6-0.5-2.8-1.4-3.8-2.5c-1-1.1-1.7-2.5-2.2-4.2c-0.5-1.7-0.6-3.7-0.6-5.9v-3c0-2.1,0.2-3.9,0.6-5.6c0.5-1.7,1.2-3.1,2.3-4.3
|
||||
c1.1-1.2,2.5-2.1,4.2-2.8c1.7-0.6,3.9-1,6.5-1c1.4,0,2.8,0.1,4.2,0.4c1.4,0.2,2.5,0.5,3.4,0.8l-1,4.7c-0.8-0.2-1.7-0.4-2.6-0.6
|
||||
C175.5,40.5,174.5,40.5,173.2,40.5z"/>
|
||||
<path class="st15" d="M208.8,35.8v29.2h-6.3V52.3h-10.3v12.8H186V35.8h6.3v11.3h10.3V35.8H208.8z"/>
|
||||
<path class="st15" d="M242.2,35.8l-0.7,5.1h-10.9V47h10.1l-0.7,5.1h-9.4v13h-6.3V35.8H242.2z"/>
|
||||
<path class="st15" d="M252.3,65.1h-6.3V35.8h6.3V65.1z"/>
|
||||
<path class="st15" d="M257.4,35.8h9.6c2.5,0,4.5,0.4,6.2,1s3,1.6,4,2.7c1,1.2,1.7,2.5,2.1,4.2c0.4,1.7,0.6,3.4,0.6,5.3v2.8
|
||||
c0,1.9-0.2,3.7-0.6,5.4c-0.4,1.7-1.1,3-2.1,4.2c-1,1.2-2.3,2.1-4,2.7c-1.7,0.6-3.7,1-6.2,1h-9.5L257.4,35.8L257.4,35.8z M263.6,60
|
||||
h2.7c1.2,0,2.2-0.1,3.1-0.4c0.9-0.3,1.7-0.8,2.2-1.4s1-1.5,1.3-2.6c0.3-1.1,0.4-2.4,0.4-4.1v-2.2c0-1.7-0.1-3-0.4-4.1
|
||||
c-0.3-1.1-0.7-1.9-1.3-2.6s-1.3-1.1-2.2-1.4c-0.9-0.2-1.9-0.4-3.1-0.4h-2.7V60z"/>
|
||||
<path class="st15" d="M302,35.8l-0.6,4.9h-11.3v6.4h10.6l-0.6,4.9h-10v8.2h11.9l-0.6,4.9h-17.6V35.8H302z"/>
|
||||
<path class="st15" d="M312.4,35.8V60h11.9l-0.7,5.1h-17.4V35.8H312.4z"/>
|
||||
<path class="st15" d="M334.6,65.1h-6.3V35.8h6.3V65.1z"/>
|
||||
<path class="st15" d="M361.6,35.8l-0.7,5.1H353v24.2h-6.3V40.9h-8.6l0.7-5.1C338.8,35.8,361.6,35.8,361.6,35.8z"/>
|
||||
<path class="st15" d="M376.5,47.2l6.1-11.4h6.4l-9.6,16.5v12.8h-6.3V52.3l-9.5-16.5h6.9L376.5,47.2z"/>
|
||||
<g>
|
||||
<path class="st15" d="M58.8,92c-5.9,0-11.7-1.2-17.1-3.4c-5.3-2.2-9.9-5.4-13.9-9.4c-4-4-7.2-8.7-9.4-13.9C16,59.7,14.8,54,14.8,48
|
||||
c0-5.9,1.2-11.7,3.4-17.1c2.2-5.3,5.4-9.9,9.4-13.9s8.7-7.2,13.9-9.4C47,5.3,52.7,4.2,58.7,4.2s11.7,1.2,17.1,3.4
|
||||
C81,9.8,85.7,13,89.7,17s7.2,8.7,9.4,13.9c2.3,5.4,3.4,11.2,3.4,17.1s-1.2,11.7-3.4,17.1c-2.2,5.3-5.4,9.9-9.4,13.9
|
||||
c-4,4-8.7,7.2-13.9,9.4C70.5,90.8,64.7,92,58.8,92z M58.8,8.7C37.1,8.7,19.4,26.4,19.4,48s17.7,39.4,39.4,39.4S98.1,69.7,98.1,48
|
||||
S80.5,8.7,58.8,8.7z"/>
|
||||
<path class="st15" d="M72.2,66.7V35.9c1.9-0.6,3.3-2.5,3.3-4.6c0-2.7-2.2-4.8-4.8-4.8c-2.7,0-4.8,2.2-4.8,4.8
|
||||
c0,2.1,1.2,3.8,3.1,4.5v14.4l-20.1-9.3V29.5c1.9-0.6,3.3-2.5,3.3-4.6c0-2.7-2.2-4.8-4.8-4.8c-2.7,0-4.8,2.2-4.8,4.8
|
||||
c0,2.1,1.2,3.8,3.1,4.5v31c-1.8,0.7-3.1,2.5-3.1,4.5c0,2.7,2.2,4.8,4.8,4.8c2.7,0,4.8-2.2,4.8-4.8c0-2.1-1.4-4-3.3-4.6V44.7
|
||||
l20.1,9.3v12.7c-1.8,0.7-3.1,2.5-3.1,4.5c0,2.7,2.2,4.8,4.8,4.8c2.7,0,4.8-2.2,4.8-4.8C75.5,69.1,74.1,67.4,72.2,66.7z"/>
|
||||
</g>
|
||||
</g>
|
||||
<path class="st16" d="M418.8,34h2.6v38.6h-2.6V34z"/>
|
||||
<path class="st16" d="M471.1,35.3v29.9h-2.7V50.8h-15.6v14.4h-2.7V35.3h2.7v13h15.6v-13H471.1z"/>
|
||||
<path class="st16" d="M480.1,55.4c0,1.5,0.2,2.7,0.4,3.8c0.3,1,0.7,1.9,1.3,2.5c0.6,0.7,1.5,1.1,2.5,1.4s2.4,0.4,4,0.4
|
||||
c0.9,0,1.8-0.1,2.8-0.2c1-0.1,1.8-0.3,2.5-0.4l-0.3,2.1c-0.6,0.2-1.5,0.4-2.5,0.5c-1,0.1-2,0.2-3,0.2c-1.9,0-3.5-0.2-4.8-0.7
|
||||
c-1.3-0.4-2.4-1.1-3.2-1.9c-0.8-0.9-1.4-1.9-1.7-3.2c-0.4-1.3-0.5-2.8-0.5-4.5v-1.6c0-1.6,0.2-3,0.5-4.3c0.3-1.3,0.9-2.4,1.6-3.3
|
||||
c0.7-0.9,1.7-1.6,2.8-2.1c1.1-0.5,2.5-0.7,4.2-0.7c1.4,0,2.7,0.2,3.7,0.7c1,0.4,1.9,1,2.6,1.8c0.7,0.8,1.2,1.7,1.5,2.7
|
||||
c0.3,1,0.5,2.2,0.5,3.5v1.2c0,0.8-0.1,1.4-0.4,1.8c-0.2,0.3-0.8,0.5-1.6,0.5H480.1z M486.5,45.4c-1.1,0-2,0.1-2.8,0.4
|
||||
c-0.8,0.3-1.5,0.7-2,1.4s-0.9,1.4-1.2,2.5c-0.3,1-0.4,2.3-0.4,3.7h12.3v-1.5c0-2.2-0.5-3.8-1.4-4.9C490.1,46,488.6,45.4,486.5,45.4z
|
||||
"/>
|
||||
<path class="st16" d="M500.8,34h2.6v31.2h-2.6V34z"/>
|
||||
<path class="st16" d="M528.3,55.5c0,1.8-0.2,3.3-0.7,4.6c-0.4,1.3-1.1,2.3-1.9,3.2c-0.8,0.8-1.8,1.4-2.9,1.8
|
||||
c-1.1,0.4-2.4,0.6-3.7,0.6c-0.7,0-1.3,0-1.8-0.1c-0.5-0.1-1.1-0.1-1.6-0.3c-0.5-0.1-1-0.3-1.5-0.5c-0.5-0.2-1-0.4-1.6-0.7V75h-2.6
|
||||
V43.7h2.2l0.3,2.9c1.5-2.3,4-3.4,7.4-3.4c1.2,0,2.4,0.2,3.4,0.5c1,0.4,1.9,1,2.6,1.8c0.7,0.8,1.3,1.9,1.7,3.2
|
||||
c0.4,1.3,0.6,2.9,0.6,4.8V55.5z M525.7,54.1c0-1.3-0.1-2.5-0.3-3.6c-0.2-1.1-0.5-2-1-2.7c-0.5-0.7-1.1-1.3-2-1.7
|
||||
c-0.8-0.4-1.8-0.6-3.1-0.6c-1.3,0-2.3,0.2-3.2,0.5c-0.9,0.3-1.5,0.8-2.1,1.4c-0.5,0.6-0.9,1.4-1.1,2.3c-0.2,0.9-0.3,2-0.3,3.2v9
|
||||
c1,0.5,1.9,0.9,2.8,1.2c0.9,0.2,2,0.4,3.2,0.4c1.3,0,2.4-0.2,3.3-0.5c0.9-0.3,1.6-0.9,2.1-1.6c0.5-0.7,0.9-1.6,1.2-2.6
|
||||
c0.2-1.1,0.4-2.3,0.4-3.6V54.1z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="main">
|
||||
|
||||
<h1>Backing Up Your Private Keys</h1>
|
||||
<hr>
|
||||
|
||||
<!-- Paragraphs -->
|
||||
<h3>What are private keys?</h3>
|
||||
<p>A private key is a secret piece of text that is used to prove ownership, unlock confidential information and sign transactions.</p>
|
||||
<p>In High Fidelity, your private keys are used to securely access the contents of your Wallet and Purchases.</p>
|
||||
|
||||
<hr>
|
||||
<h3>Where are my private keys stored?"</h3>
|
||||
<p>By default, your private keys are only stored on your hard drive in High Fidelity Interface's <code>AppData</code> directory.</p>
|
||||
<p>Here is the file path of your hifikey - you can browse to it using your file explorer.</p>
|
||||
<div class="alert"> <code>HIFIKEY_PATH_REPLACEME</code> </div>
|
||||
|
||||
<hr>
|
||||
<h3>How should I make a backup of my private keys?</h3>
|
||||
<p>You should backup your <code>.hifikey</code> file above by copying it to a USB flash drive, or to a service like Dropbox or Google Drive. Restore your backup by replacing the file in Interface's AppData directory with your backed-up copy.</p>
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 497.3 186.1" style="enable-background:new 0 0 497.3 186.1;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#CECECE;}
|
||||
.st1{fill:#FFFFFF;}
|
||||
.st2{fill:#FEFEFE;}
|
||||
.st3{fill:#0DA860;}
|
||||
.st4{fill:#F9C942;}
|
||||
.st5{fill:#367CF3;}
|
||||
.st6{fill:#2D6FDC;}
|
||||
.st7{fill:#E4B83D;}
|
||||
.st8{fill:#08137C;}
|
||||
.st9{fill:#EF3B4E;}
|
||||
.st10{fill:#B8355B;}
|
||||
.st11{fill:#A7C5D1;}
|
||||
.st12{fill:#7C909B;}
|
||||
.st13{fill:#CBF2FD;}
|
||||
.st14{fill:#000222;}
|
||||
</style>
|
||||
<circle class="st0" cx="255" cy="69.5" r="61.1"/>
|
||||
<circle class="st0" cx="88" cy="69.5" r="61.1"/>
|
||||
<circle class="st1" cx="88" cy="65.5" r="61.1"/>
|
||||
<path class="st2" d="M133.4,78c0-0.1-0.1-0.2-0.1-0.3c-5-8.7-10-17.4-15-26c-4.7-8.2-9.4-16.3-14.1-24.5c-0.2-0.3-0.4-0.4-0.7-0.4
|
||||
c-10.2,0-20.4,0-30.6,0c-0.2,0-0.3,0-0.5,0c-0.1,0.1-0.2,0.2-0.2,0.3c-9.7,16.8-19.4,33.6-29.1,50.5c-0.2,0.3-0.2,0.5,0,0.8
|
||||
c4.2,7.2,8.4,14.5,12.6,21.7c1,1.7,2,3.5,3,5.2c0.1,0.1,0.3,0.1,0.5,0.1c19.4,0,38.8,0,58.2,0c0.4,0,0.6-0.1,0.8-0.4
|
||||
c4.3-7.4,8.6-14.9,12.9-22.3C131.6,81.1,132.5,79.6,133.4,78z"/>
|
||||
<path class="st3" d="M58.5,105.3c-1-1.7-2-3.4-3-5.2c-4.2-7.2-8.4-14.5-12.6-21.7c-0.2-0.3-0.2-0.5,0-0.8
|
||||
C52.6,60.8,62.3,43.9,72,27.1c0.1-0.1,0.1-0.2,0.2-0.3c0.1,0.1,0.2,0.2,0.2,0.4c5.1,8.9,10.3,17.8,15.4,26.6
|
||||
c0.1,0.1,0.2,0.2,0.2,0.4c-0.1,0.1-0.2,0.2-0.2,0.3c-3.2,5.5-6.4,11-9.6,16.5c-1.3,2.3-2.6,4.6-4,6.9c-0.1,0.1-0.2,0.2-0.2,0.3
|
||||
c-1.9,3.3-3.8,6.6-5.7,9.9c-2.7,4.7-5.5,9.4-8.2,14.2c-0.5,0.9-1.1,1.8-1.5,2.7c0,0,0,0,0,0c0,0.1-0.1,0.1-0.1,0.2
|
||||
C58.6,105.2,58.5,105.3,58.5,105.3z"/>
|
||||
<path class="st4" d="M88.1,54.2c0-0.2-0.1-0.3-0.2-0.4C82.8,44.9,77.6,36,72.5,27.2c-0.1-0.1-0.2-0.2-0.2-0.4c0.2-0.1,0.3,0,0.5,0
|
||||
c10.2,0,20.4,0,30.6,0c0.3,0,0.5,0.1,0.7,0.4c4.7,8.2,9.4,16.3,14.1,24.5c5,8.7,10,17.4,15,26c0.1,0.1,0.1,0.2,0.1,0.3
|
||||
c-0.1,0-0.1,0-0.2,0c0-0.1-0.1-0.1-0.2-0.1c-3.6-1.1-7.2-2.2-10.7-3.3c-2.5-0.8-4.9-1.5-7.4-2.3c-4.2-1.3-8.4-2.6-12.6-3.9
|
||||
c-2.3-0.7-4.6-1.4-6.8-2.1c-0.1,0-0.3-0.1-0.4,0c0,0-0.1-0.1-0.1-0.1c-1.6-2.7-3.1-5.4-4.7-8.1C89.6,56.8,88.8,55.5,88.1,54.2z"/>
|
||||
<path class="st5" d="M133.2,78c0.1,0,0.1,0,0.2,0c-0.9,1.5-1.8,3.1-2.6,4.6c-4.3,7.4-8.6,14.8-12.9,22.3c-0.2,0.3-0.4,0.4-0.8,0.4
|
||||
c-19.4,0-38.8,0-58.2,0c-0.2,0-0.3,0.1-0.5-0.1c0,0,0.1-0.1,0.1-0.1c0.1,0,0.1-0.1,0.1-0.2c0,0,0,0,0,0c0.3-0.1,0.5-0.3,0.8-0.5
|
||||
c1.1-1,2.3-2.1,3.4-3.2c1.6-1.5,3.2-3,4.8-4.5c1.1-1.1,2.3-2.1,3.4-3.2c1.6-1.5,3.3-3,4.9-4.5c1.2-1.1,2.3-2.1,3.5-3.2
|
||||
c1.8-1.7,3.6-3.4,5.4-5c0.8-0.8,1.7-1.5,2.5-2.4c0.2-0.2,0.5-0.2,0.5-0.5c1.5,0,3,0,4.5,0c3.1,0,6.2,0,9.3,0
|
||||
c0.2,0.1,0.3,0.1,0.5,0.1c10.1,0,20.3,0,30.4,0C132.9,78,133.1,78,133.2,78z"/>
|
||||
<path class="st2" d="M101.8,78c-3.1,0-6.2,0-9.3,0c-1.5,0-3,0-4.5,0c-0.2,0-0.4,0-0.5,0c-3.9,0-7.8,0-11.7,0c-0.5,0-0.9,0-1.4,0
|
||||
c1.3-2.3,2.6-4.6,4-6.9c3.2-5.5,6.4-11,9.6-16.5c0.1-0.1,0.1-0.2,0.2-0.3c0.8,1.3,1.5,2.6,2.3,3.9c1.6,2.7,3.1,5.4,4.7,8.1
|
||||
c0,0,0.1,0.1,0.1,0.1c1.2,2,2.3,4,3.5,6C99.6,74.2,100.7,76.1,101.8,78z"/>
|
||||
<path class="st6" d="M74.3,78c0.5,0,0.9,0,1.4,0c3.9,0,7.8,0,11.7,0c0.2,0,0.4,0,0.5,0c-0.1,0.3-0.3,0.4-0.5,0.5
|
||||
c-0.8,0.8-1.7,1.6-2.5,2.4c-1.8,1.7-3.6,3.4-5.4,5c-1.2,1.1-2.3,2.1-3.5,3.2c-1.6,1.5-3.2,3-4.9,4.5c-1.2,1.1-2.3,2.1-3.4,3.2
|
||||
c-1.6,1.5-3.2,3-4.8,4.5c-1.1,1.1-2.3,2.1-3.4,3.2c-0.2,0.2-0.4,0.4-0.8,0.5c0.4-0.9,1-1.8,1.5-2.7c2.7-4.7,5.4-9.4,8.2-14.2
|
||||
c1.9-3.3,3.8-6.6,5.7-9.9C74.2,78.1,74.2,78.1,74.3,78z"/>
|
||||
<path class="st6" d="M58.7,105c0,0.1,0,0.2-0.1,0.2C58.6,105.1,58.7,105.1,58.7,105z"/>
|
||||
<path class="st7" d="M101.8,78c-1.1-1.9-2.2-3.8-3.3-5.7c-1.1-2-2.3-4-3.5-6c0.1-0.2,0.3-0.1,0.4,0c2.3,0.7,4.6,1.4,6.8,2.1
|
||||
c4.2,1.3,8.4,2.6,12.6,3.9c2.5,0.8,4.9,1.5,7.4,2.3c3.6,1.1,7.2,2.2,10.7,3.3c0.1,0,0.2,0,0.2,0.1c-0.2,0-0.3,0-0.5,0
|
||||
c-10.1,0-20.3,0-30.4,0C102.1,78,101.9,78.1,101.8,78z"/>
|
||||
<g>
|
||||
<path class="st1" d="M315.5,65.6c0.1-33.6-27.3-60.9-61-61c-33.6-0.1-61,27.2-61,60.9c-0.1,33.6,27.2,61,61,61.1
|
||||
C288.1,126.6,315.5,99.3,315.5,65.6z"/>
|
||||
<path class="st1" d="M315.5,65.6c-0.1,33.7-27.4,61.1-61,61c-33.7-0.1-61-27.4-61-61.1c0.1-33.7,27.4-61,61-60.9
|
||||
C288.3,4.6,315.6,31.9,315.5,65.6z M297.6,45.8c-0.1-0.1-0.2-0.1-0.3-0.2c-7-4.4-14-8.9-20.9-13.4c-0.3-0.2-0.4-0.1-0.7,0
|
||||
c-6.9,4.4-13.9,8.8-20.8,13.3c-0.4,0.3-0.4,0.3,0,0.5c6.9,4.4,13.8,8.8,20.7,13.2c0.1,0.1,0.3,0.2,0.4,0.3
|
||||
c-7.2,4.6-14.3,9.1-21.5,13.7c0.2,0.1,0.3,0.2,0.5,0.3c6.9,4.4,13.8,8.8,20.7,13.2c0.3,0.2,0.5,0.2,0.8,0c6.7-4.3,13.3-8.5,20-12.7
|
||||
c0.4-0.2,0.8-0.5,1.2-0.8c-7.2-4.6-14.4-9.1-21.6-13.7C283.2,55,290.4,50.4,297.6,45.8z M254.5,73.3c-7.2-4.6-14.4-9.2-21.6-13.7
|
||||
c0.2-0.1,0.4-0.2,0.5-0.3c6.9-4.4,13.7-8.7,20.6-13.1c0.4-0.3,0.4-0.3,0-0.6c-6.9-4.4-13.8-8.8-20.7-13.2c-0.3-0.2-0.5-0.2-0.8,0
|
||||
c-6.9,4.4-13.8,8.8-20.7,13.2c-0.4,0.3-0.4,0.3,0,0.6c5.3,3.4,10.6,6.8,15.9,10.1c1.7,1.1,3.4,2.2,5.2,3.3
|
||||
c-7.2,4.6-14.4,9.1-21.6,13.7c0.2,0.1,0.3,0.2,0.5,0.3c6.9,4.4,13.8,8.8,20.7,13.2c0.3,0.2,0.5,0.2,0.8,0
|
||||
c5.1-3.3,10.2-6.5,15.4-9.8C250.6,75.8,252.5,74.5,254.5,73.3z M275.9,91.6c-0.1-0.1-0.2-0.2-0.3-0.2c-6.9-4.4-13.9-8.8-20.8-13.3
|
||||
c-0.2-0.2-0.4-0.2-0.7,0c-6.9,4.4-13.9,8.9-20.8,13.3c-0.1,0.1-0.2,0.2-0.4,0.3c0.2,0.1,0.3,0.2,0.4,0.3
|
||||
c6.9,4.4,13.9,8.8,20.8,13.3c0.3,0.2,0.5,0.1,0.7,0c6.9-4.4,13.8-8.8,20.7-13.2C275.7,91.8,275.8,91.7,275.9,91.6z"/>
|
||||
<path class="st8" d="M297.6,45.8c-7.2,4.6-14.4,9.1-21.6,13.7c7.2,4.6,14.4,9.1,21.6,13.7c-0.4,0.3-0.8,0.5-1.2,0.8
|
||||
c-6.7,4.2-13.3,8.5-20,12.7c-0.3,0.2-0.5,0.2-0.8,0c-6.9-4.4-13.8-8.8-20.7-13.2c-0.1-0.1-0.3-0.2-0.5-0.3
|
||||
c7.2-4.6,14.3-9.1,21.5-13.7c-0.2-0.1-0.3-0.2-0.4-0.3c-6.9-4.4-13.8-8.8-20.7-13.2c-0.4-0.3-0.4-0.3,0-0.5
|
||||
c6.9-4.4,13.9-8.8,20.8-13.3c0.2-0.2,0.4-0.2,0.7,0c7,4.5,14,8.9,20.9,13.4C297.4,45.7,297.4,45.7,297.6,45.8z"/>
|
||||
<path class="st8" d="M254.5,73.3c-2,1.3-3.9,2.5-5.8,3.7c-5.1,3.3-10.3,6.5-15.4,9.8c-0.3,0.2-0.5,0.2-0.8,0
|
||||
c-6.9-4.4-13.8-8.8-20.7-13.2c-0.1-0.1-0.3-0.2-0.5-0.3c7.2-4.6,14.3-9.1,21.6-13.7c-1.8-1.1-3.5-2.2-5.2-3.3
|
||||
c-5.3-3.4-10.6-6.8-15.9-10.1c-0.4-0.3-0.4-0.3,0-0.6c6.9-4.4,13.8-8.8,20.7-13.2c0.3-0.2,0.5-0.2,0.8,0
|
||||
c6.9,4.4,13.8,8.8,20.7,13.2c0.4,0.3,0.4,0.3,0,0.6c-6.9,4.4-13.7,8.7-20.6,13.1c-0.2,0.1-0.3,0.2-0.5,0.3
|
||||
C240.1,64.1,247.2,68.7,254.5,73.3z"/>
|
||||
<path class="st8" d="M275.9,91.6c-0.1,0.2-0.3,0.2-0.4,0.3c-6.9,4.4-13.8,8.8-20.7,13.2c-0.2,0.2-0.4,0.2-0.7,0
|
||||
c-6.9-4.4-13.9-8.9-20.8-13.3c-0.1-0.1-0.2-0.1-0.4-0.3c0.1-0.1,0.3-0.2,0.4-0.3c6.9-4.4,13.9-8.8,20.8-13.3c0.3-0.2,0.4-0.1,0.7,0
|
||||
c6.9,4.4,13.9,8.9,20.8,13.3C275.7,91.4,275.8,91.5,275.9,91.6z"/>
|
||||
</g>
|
||||
<path class="st9" d="M389.9,117c-6.8-6.8-13.7-13.6-20.5-20.5c-1.9-2-1.8-5.6,0.1-7.7c0.2-0.3,0.5-0.5,0.8-0.8
|
||||
c15.9-15.9,31.8-31.7,47.6-47.6c2.6-2.6,5.9-1.9,7.8-0.1c0.3,0.3,0.6,0.6,0.9,0.9c6.2,6.2,12.5,12.5,18.7,18.7
|
||||
c0.3,0.3,0.6,0.6,0.9,1c0.1,0.3,0.3,0.6,0.4,0.8c0.8,1.7,0.4,4-0.9,5.2c-16.4,16.3-32.7,32.7-49.1,49c-0.2,0.2-0.4,0.4-0.7,0.6
|
||||
C394,117.8,392,117.9,389.9,117z M423.3,62.2c-2,0.5-3.9,1-5.8,1.6c-1.6,0.4-1.6,0.4-0.4,1.6c0.4,0.4,0.5,0.7,0,1.1
|
||||
c-5,5-9.9,9.9-14.9,14.9c-0.1,0.1-0.3,0.4-0.5,0.2c-0.1-0.1-0.1-0.3-0.1-0.5c0-1.5-0.1-2.9-0.1-4.4c0-0.6,0.2-1.1,0.7-1.6
|
||||
c1.2-1.2,2.4-2.4,3.6-3.6c0.3-0.3,0.6-0.5,1.2-0.4c1.7,0.2,3.2-1.2,3.2-2.9c0-1.9-1.4-3.2-3.2-3.1c-1.8,0.1-3.1,1.6-2.8,3.4
|
||||
c0.1,0.4-0.1,0.7-0.4,1c-1.2,1.1-2.3,2.3-3.5,3.4c-1.2,1.1-1.7,2.4-1.6,4c0.1,2.2,0.1,4.5,0.1,6.7c0,1.3-1,2-1.7,2.7
|
||||
c-0.5,0.5-1,0-1.5-0.1c-2.2-0.5-4.4,0.7-5.3,2.7c-0.9,2.2-0.1,4.5,1.8,5.7c1.8,1.1,3.8,0.9,5.6-0.5c1.2-1,1.8-3.1,1.2-4.9
|
||||
c-0.2-0.6-0.1-1,0.3-1.4c1.7-1.6,3.3-3.3,4.9-4.9c0.5-0.5,1-0.7,1.6-0.7c2.1,0,4.2,0,6.3,0.2c1.7,0.1,3.3-0.3,4.5-1.6
|
||||
c0.4-0.5,0.9-0.9,1.4-1.4c0.5-0.6,0.9-0.6,1.3,0c0.3,0.4,0.6,0.5,1,0c1.1-1.1,2.2-2.2,3.3-3.3c0.4-0.4,0.4-0.6,0-1
|
||||
c-1.1-1.1-2.2-2.2-3.3-3.3c-0.4-0.4-0.7-0.3-1,0.1c-1,1-2,2.1-3.1,3.1c-0.5,0.5-0.7,0.8,0,1.3c0.3,0.2,0.6,0.5,0.2,0.9
|
||||
c-0.6,0.6-1.3,1.3-1.9,1.9c-0.4,0.3-0.9,0.6-1.5,0.5c-1.5-0.2-2.9-0.1-4.4-0.1c-0.2,0-0.5,0.1-0.6-0.1c0-0.1,0-0.1,0-0.2
|
||||
c3.7-3.7,7.4-7.4,11.1-11.1c0.4-0.4,0.6-0.2,0.9,0.1c1.3,1.2,1.3,1.1,1.7-0.5C422.3,66,422.8,64.1,423.3,62.2z"/>
|
||||
<path class="st10" d="M389.9,117c2.1,0.9,4.1,0.9,6-0.4c0.3-0.2,0.5-0.4,0.7-0.6c16.4-16.3,32.7-32.7,49.1-49
|
||||
c1.3-1.3,1.7-3.5,0.9-5.2c-0.1-0.3-0.2-0.6-0.4-0.8c1.4,1.4,2.7,2.7,4.1,4.1c0.6,0.6,1.3,1.2,1.8,1.9c1.7,2.2,1.5,4.8-0.5,6.8
|
||||
c-7.8,7.8-15.7,15.7-23.5,23.5c-8.3,8.3-16.5,16.5-24.8,24.8c-1,1-2.1,1.6-3.4,1.9c-1.8,0.3-3.4-0.1-4.7-1.4
|
||||
C393.5,120.5,391.7,118.8,389.9,117z"/>
|
||||
<path class="st11" d="M445.3,59.9c-6.2-6.2-12.5-12.5-18.7-18.7c5-5,10.1-10,15.1-15.1c0.6-0.6,0.8-0.6,1.4,0c6,6,12,12,18,18
|
||||
C455.9,49.4,450.6,54.7,445.3,59.9z M439.3,37.5c-0.5-0.5-0.9-1-1.4-1.4c-0.5-0.5-1.1-0.5-1.6,0c-0.4,0.4-0.8,0.8-1.2,1.2
|
||||
c-0.5,0.6-0.5,1.1,0,1.7c0.5,0.6,1.1,1.1,1.7,1.7c2,2.2,2,1.7,3.9-0.1c0,0,0,0,0.1-0.1c0.5-0.5,0.5-1.1,0-1.6
|
||||
C440.3,38.4,439.8,38,439.3,37.5z M449,47.2c-0.5-0.5-1-1-1.5-1.5c-0.7-0.6-1.1-0.5-2.5,1c-0.8,0.8-0.9,1.3-0.3,1.9
|
||||
c0.9,1,1.9,1.9,2.9,2.9c0.7,0.6,1.1,0.5,2.5-1c0.8-0.8,0.9-1.3,0.3-1.9C449.9,48.1,449.5,47.6,449,47.2z"/>
|
||||
<path class="st12" d="M445.3,59.9c5.3-5.3,10.5-10.5,15.8-15.8c1.5,1.5,3,3,4.5,4.4c0.5,0.5,0.4,0.7,0,1.1
|
||||
c-4.9,4.8-9.7,9.7-14.6,14.5c-0.2,0.2-0.5,0.5-0.7,0.7c-1.4-1.4-2.7-2.7-4.1-4.1C445.9,60.6,445.6,60.2,445.3,59.9z"/>
|
||||
<path class="st1" d="M423.3,62.2c-0.5,2-1,3.8-1.5,5.6c-0.5,1.7-0.5,1.7-1.7,0.5c-0.3-0.3-0.6-0.4-0.9-0.1
|
||||
c-3.7,3.7-7.4,7.4-11.1,11.1c0,0,0,0.1,0,0.2c0.2,0.2,0.4,0.1,0.6,0.1c1.5,0.1,2.9-0.1,4.4,0.1c0.6,0.1,1.1-0.2,1.5-0.5
|
||||
c0.7-0.6,1.3-1.2,1.9-1.9c0.4-0.4,0.1-0.7-0.2-0.9c-0.6-0.5-0.5-0.8,0-1.3c1.1-1,2.1-2,3.1-3.1c0.4-0.4,0.6-0.5,1-0.1
|
||||
c1.1,1.1,2.2,2.2,3.3,3.3c0.4,0.4,0.4,0.6,0,1c-1.1,1.1-2.2,2.2-3.3,3.3c-0.4,0.4-0.7,0.4-1,0c-0.5-0.6-0.9-0.6-1.3,0
|
||||
c-0.4,0.5-0.9,0.9-1.4,1.4c-1.2,1.4-2.7,1.7-4.5,1.6c-2.1-0.1-4.2-0.1-6.3-0.2c-0.6,0-1.2,0.3-1.6,0.7c-1.6,1.7-3.3,3.3-4.9,4.9
|
||||
c-0.4,0.4-0.6,0.8-0.3,1.4c0.6,1.7,0,3.9-1.2,4.9c-1.8,1.4-3.8,1.6-5.6,0.5c-2-1.2-2.7-3.6-1.8-5.7c0.8-2.1,3.1-3.2,5.3-2.7
|
||||
c0.5,0.1,1,0.6,1.5,0.1c0.8-0.8,1.8-1.4,1.7-2.7c-0.1-2.2-0.1-4.5-0.1-6.7c0-1.6,0.5-2.9,1.6-4c1.2-1.1,2.3-2.3,3.5-3.4
|
||||
c0.3-0.3,0.4-0.6,0.4-1c-0.2-1.8,1.1-3.3,2.8-3.4c1.8-0.1,3.2,1.3,3.2,3.1c0,1.7-1.5,3.1-3.2,2.9c-0.5-0.1-0.8,0.1-1.2,0.4
|
||||
c-1.2,1.2-2.4,2.4-3.6,3.6c-0.5,0.4-0.7,0.9-0.7,1.6c0,1.5,0.1,2.9,0.1,4.4c0,0.2,0,0.4,0.1,0.5c0.2,0.1,0.3-0.1,0.5-0.2
|
||||
c5-5,9.9-9.9,14.9-14.9c0.4-0.4,0.4-0.7,0-1.1c-1.1-1.2-1.1-1.2,0.4-1.6C419.4,63.2,421.3,62.7,423.3,62.2z"/>
|
||||
<path class="st13" d="M439.3,37.5c0.5,0.5,0.9,0.9,1.4,1.4c0.5,0.5,0.5,1,0,1.6c0,0,0,0-0.1,0.1c-1.9,1.9-1.9,2.3-3.9,0.1
|
||||
c-0.5-0.6-1.1-1.1-1.7-1.7c-0.6-0.6-0.6-1.1,0-1.7c0.4-0.4,0.8-0.8,1.2-1.2c0.5-0.5,1.1-0.5,1.6,0C438.4,36.6,438.9,37.1,439.3,37.5
|
||||
z"/>
|
||||
<path class="st13" d="M449,47.2c0.5,0.5,0.9,0.9,1.4,1.4c0.6,0.6,0.5,1.1-0.3,1.9c-1.4,1.5-1.8,1.6-2.5,1c-1-0.9-1.9-1.9-2.9-2.9
|
||||
c-0.6-0.6-0.5-1.1,0.3-1.9c1.4-1.5,1.8-1.6,2.5-1C448,46.2,448.5,46.7,449,47.2z"/>
|
||||
<g>
|
||||
<path class="st14" d="M32.1,158.8l0.2-1.2h4.2v7.7c-0.2,0.1-0.5,0.2-0.8,0.3c-0.3,0.1-0.7,0.2-1,0.2c-0.4,0.1-0.7,0.1-1.1,0.1
|
||||
s-0.7,0-1,0c-1.4,0-2.6-0.2-3.5-0.5c-0.9-0.4-1.5-0.8-2-1.5c-0.5-0.6-0.8-1.4-0.9-2.3c-0.1-0.9-0.2-1.9-0.2-2.9v-1.6
|
||||
c0-1.2,0.1-2.2,0.3-3.1c0.2-0.9,0.6-1.7,1.1-2.3s1.2-1.1,2.1-1.4c0.9-0.3,2-0.5,3.3-0.5c0.6,0,1.2,0.1,1.8,0.2
|
||||
c0.6,0.1,1.1,0.2,1.6,0.4l-0.3,1.1c-0.4-0.1-0.9-0.2-1.4-0.3c-0.5-0.1-1.1-0.1-1.7-0.1c-1,0-1.8,0.1-2.4,0.3s-1.2,0.5-1.6,1
|
||||
c-0.4,0.5-0.7,1.1-0.9,1.9s-0.3,1.8-0.3,3v1.5c0,1.2,0.1,2.1,0.3,2.9c0.2,0.8,0.5,1.4,0.9,1.8c0.4,0.5,0.9,0.8,1.6,1
|
||||
c0.7,0.2,1.5,0.3,2.4,0.3c0.5,0,0.9,0,1.4-0.1c0.4,0,0.8-0.1,1.2-0.2v-5.6H32.1z"/>
|
||||
<path class="st14" d="M44.5,154.2c1,0,1.7,0.1,2.4,0.4c0.6,0.2,1.1,0.6,1.5,1.1c0.4,0.5,0.6,1,0.8,1.7c0.2,0.7,0.2,1.4,0.2,2.2v1.2
|
||||
c0,0.8-0.1,1.5-0.3,2.2c-0.2,0.7-0.5,1.2-0.8,1.7c-0.4,0.5-0.9,0.8-1.5,1.1c-0.6,0.2-1.4,0.4-2.3,0.4c-1,0-1.7-0.1-2.4-0.4
|
||||
c-0.6-0.2-1.1-0.6-1.5-1.1s-0.6-1-0.8-1.7c-0.2-0.7-0.2-1.4-0.2-2.2v-1.2c0-0.8,0.1-1.5,0.3-2.2c0.2-0.7,0.5-1.2,0.9-1.7
|
||||
s0.9-0.8,1.5-1.1C42.8,154.3,43.6,154.2,44.5,154.2z M44.5,164.8c0.7,0,1.2-0.1,1.7-0.2s0.8-0.4,1.1-0.7c0.3-0.3,0.5-0.8,0.6-1.3
|
||||
c0.1-0.5,0.2-1.2,0.2-1.9v-1c0-0.8-0.1-1.4-0.2-2s-0.3-1-0.6-1.3c-0.3-0.3-0.6-0.6-1.1-0.7s-1-0.2-1.6-0.2c-0.7,0-1.2,0.1-1.7,0.2
|
||||
c-0.5,0.2-0.8,0.4-1.1,0.7c-0.3,0.3-0.5,0.8-0.6,1.3c-0.1,0.5-0.2,1.2-0.2,1.9v1c0,0.8,0.1,1.4,0.2,1.9c0.1,0.5,0.3,1,0.6,1.3
|
||||
c0.3,0.3,0.6,0.6,1.1,0.7C43.2,164.7,43.8,164.8,44.5,164.8z"/>
|
||||
<path class="st14" d="M57.1,154.2c1,0,1.7,0.1,2.4,0.4c0.6,0.2,1.1,0.6,1.5,1.1c0.4,0.5,0.6,1,0.8,1.7c0.2,0.7,0.2,1.4,0.2,2.2v1.2
|
||||
c0,0.8-0.1,1.5-0.3,2.2c-0.2,0.7-0.5,1.2-0.8,1.7c-0.4,0.5-0.9,0.8-1.5,1.1c-0.6,0.2-1.4,0.4-2.3,0.4c-1,0-1.7-0.1-2.4-0.4
|
||||
c-0.6-0.2-1.1-0.6-1.5-1.1s-0.6-1-0.8-1.7c-0.2-0.7-0.2-1.4-0.2-2.2v-1.2c0-0.8,0.1-1.5,0.3-2.2c0.2-0.7,0.5-1.2,0.9-1.7
|
||||
s0.9-0.8,1.5-1.1C55.4,154.3,56.2,154.2,57.1,154.2z M57.1,164.8c0.7,0,1.2-0.1,1.7-0.2s0.8-0.4,1.1-0.7c0.3-0.3,0.5-0.8,0.6-1.3
|
||||
c0.1-0.5,0.2-1.2,0.2-1.9v-1c0-0.8-0.1-1.4-0.2-2s-0.3-1-0.6-1.3c-0.3-0.3-0.6-0.6-1.1-0.7s-1-0.2-1.6-0.2c-0.7,0-1.2,0.1-1.7,0.2
|
||||
c-0.5,0.2-0.8,0.4-1.1,0.7c-0.3,0.3-0.5,0.8-0.6,1.3c-0.1,0.5-0.2,1.2-0.2,1.9v1c0,0.8,0.1,1.4,0.2,1.9c0.1,0.5,0.3,1,0.6,1.3
|
||||
c0.3,0.3,0.6,0.6,1.1,0.7C55.9,164.7,56.4,164.8,57.1,164.8z"/>
|
||||
<path class="st14" d="M74.3,165.5c0,0.8-0.1,1.6-0.3,2.3c-0.2,0.7-0.5,1.2-0.9,1.7c-0.4,0.5-0.9,0.8-1.6,1.1
|
||||
c-0.6,0.2-1.4,0.4-2.3,0.4c-1.3,0-2.7-0.2-4-0.6l0.3-1.1c0.6,0.2,1.2,0.3,1.8,0.4c0.6,0.1,1.2,0.1,1.9,0.1s1.3-0.1,1.8-0.3
|
||||
c0.5-0.2,0.8-0.5,1.1-0.9c0.3-0.4,0.5-0.9,0.6-1.4c0.1-0.6,0.2-1.2,0.2-1.9v-1.3c-0.1,0.2-0.3,0.5-0.5,0.7
|
||||
c-0.2,0.2-0.5,0.4-0.8,0.6c-0.3,0.2-0.7,0.3-1.1,0.4c-0.4,0.1-0.9,0.1-1.5,0.1c-0.6,0-1.2-0.1-1.8-0.3c-0.5-0.2-1-0.5-1.4-0.9
|
||||
c-0.4-0.4-0.7-1-0.9-1.6c-0.2-0.7-0.3-1.5-0.3-2.5v-0.7c0-0.9,0.1-1.7,0.4-2.4s0.6-1.2,1.1-1.7c0.5-0.5,1-0.8,1.6-1
|
||||
c0.6-0.2,1.3-0.3,2.1-0.3c0.8,0,1.6,0.1,2.3,0.3c0.7,0.2,1.4,0.4,2,0.8V165.5z M66.1,160.1c0,0.7,0.1,1.3,0.2,1.9s0.3,1,0.5,1.4
|
||||
c0.3,0.4,0.6,0.7,1,0.8s0.9,0.3,1.6,0.3c1.2,0,2.1-0.3,2.7-0.9c0.6-0.6,0.9-1.6,0.9-3V156c-0.4-0.2-0.8-0.4-1.3-0.5
|
||||
c-0.4-0.1-1-0.2-1.6-0.2c-1.3,0-2.3,0.3-3,1s-1,1.8-1,3.4V160.1z"/>
|
||||
<path class="st14" d="M77.8,149.3h1.3v16.3h-1.3V149.3z"/>
|
||||
<path class="st14" d="M83.6,160.5c0,0.8,0.1,1.4,0.2,2c0.1,0.5,0.4,1,0.7,1.3c0.3,0.3,0.8,0.6,1.3,0.7c0.5,0.2,1.2,0.2,2.1,0.2
|
||||
c0.5,0,0.9,0,1.5-0.1c0.5-0.1,1-0.1,1.3-0.2l-0.2,1.1c-0.3,0.1-0.8,0.2-1.3,0.3c-0.5,0.1-1.1,0.1-1.6,0.1c-1,0-1.8-0.1-2.5-0.3
|
||||
c-0.7-0.2-1.2-0.6-1.7-1s-0.7-1-0.9-1.7c-0.2-0.7-0.3-1.5-0.3-2.4v-0.9c0-0.8,0.1-1.6,0.3-2.3c0.2-0.7,0.5-1.3,0.8-1.7
|
||||
c0.4-0.5,0.9-0.9,1.5-1.1c0.6-0.3,1.3-0.4,2.2-0.4c0.7,0,1.4,0.1,1.9,0.3c0.5,0.2,1,0.5,1.3,0.9s0.6,0.9,0.8,1.4
|
||||
c0.2,0.5,0.2,1.2,0.2,1.8v0.6c0,0.4-0.1,0.7-0.2,0.9c-0.1,0.2-0.4,0.3-0.8,0.3H83.6z M86.9,155.3c-0.6,0-1,0.1-1.5,0.2
|
||||
s-0.8,0.4-1,0.7c-0.3,0.3-0.5,0.8-0.6,1.3c-0.1,0.5-0.2,1.2-0.2,2h6.5v-0.8c0-1.1-0.2-2-0.7-2.6S88,155.3,86.9,155.3z"/>
|
||||
<path class="st14" d="M100.2,150h4.9c1.3,0,2.3,0.2,3.1,0.5c0.8,0.3,1.5,0.8,2,1.4c0.5,0.6,0.8,1.3,1,2.2c0.2,0.8,0.3,1.7,0.3,2.7
|
||||
v2c0,1-0.1,1.9-0.3,2.8c-0.2,0.8-0.6,1.6-1.1,2.2c-0.5,0.6-1.1,1.1-2,1.4s-1.8,0.5-3.1,0.5h-4.8V150z M101.6,164.5h3.3
|
||||
c0.8,0,1.5-0.1,2.2-0.3c0.6-0.2,1.2-0.5,1.6-0.9c0.4-0.4,0.8-1,1-1.8c0.2-0.7,0.3-1.6,0.3-2.8V157c0-1.1-0.1-2-0.3-2.7
|
||||
c-0.2-0.7-0.5-1.3-0.9-1.8c-0.4-0.4-0.9-0.8-1.6-1c-0.6-0.2-1.4-0.3-2.2-0.3h-3.4V164.5z"/>
|
||||
<path class="st14" d="M120.7,155.6c-0.2,0-0.4-0.1-0.7-0.1c-0.2,0-0.4,0-0.6,0c-1.1,0-1.9,0.3-2.4,1c-0.5,0.7-0.8,1.7-0.8,3.2v6.1
|
||||
h-1.4v-11.2h1.1l0.2,1.8c0.7-1.3,1.9-1.9,3.5-1.9c0.2,0,0.5,0,0.7,0.1c0.2,0,0.4,0.1,0.6,0.1L120.7,155.6z"/>
|
||||
<path class="st14" d="M123.8,150.1c0.7,0,1,0.3,1,1c0,0.6-0.3,1-1,1c-0.6,0-1-0.3-1-1C122.9,150.4,123.2,150.1,123.8,150.1z
|
||||
M123.2,154.4h1.4v11.2h-1.4V154.4z"/>
|
||||
<path class="st14" d="M127.1,154.4h1.5l3.8,9.9l3.8-9.9h1.5l-4.5,11.2h-1.5L127.1,154.4z"/>
|
||||
<path class="st14" d="M140.6,160.5c0,0.8,0.1,1.4,0.2,2c0.1,0.5,0.4,1,0.7,1.3c0.3,0.3,0.8,0.6,1.3,0.7c0.5,0.2,1.2,0.2,2.1,0.2
|
||||
c0.5,0,0.9,0,1.5-0.1c0.5-0.1,1-0.1,1.3-0.2l-0.2,1.1c-0.3,0.1-0.8,0.2-1.3,0.3c-0.5,0.1-1.1,0.1-1.6,0.1c-1,0-1.8-0.1-2.5-0.3
|
||||
c-0.7-0.2-1.2-0.6-1.7-1s-0.7-1-0.9-1.7c-0.2-0.7-0.3-1.5-0.3-2.4v-0.9c0-0.8,0.1-1.6,0.3-2.3c0.2-0.7,0.5-1.3,0.8-1.7
|
||||
c0.4-0.5,0.9-0.9,1.5-1.1c0.6-0.3,1.3-0.4,2.2-0.4c0.7,0,1.4,0.1,1.9,0.3c0.5,0.2,1,0.5,1.3,0.9s0.6,0.9,0.8,1.4
|
||||
c0.2,0.5,0.2,1.2,0.2,1.8v0.6c0,0.4-0.1,0.7-0.2,0.9c-0.1,0.2-0.4,0.3-0.8,0.3H140.6z M143.9,155.3c-0.6,0-1,0.1-1.5,0.2
|
||||
s-0.8,0.4-1,0.7c-0.3,0.3-0.5,0.8-0.6,1.3c-0.1,0.5-0.2,1.2-0.2,2h6.5v-0.8c0-1.1-0.2-2-0.7-2.6S145,155.3,143.9,155.3z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st14" d="M217.3,150h4.9c1.3,0,2.3,0.2,3.1,0.5c0.8,0.3,1.5,0.8,2,1.4c0.5,0.6,0.8,1.3,1,2.2c0.2,0.8,0.3,1.7,0.3,2.7
|
||||
v2c0,1-0.1,1.9-0.3,2.8c-0.2,0.8-0.6,1.6-1.1,2.2c-0.5,0.6-1.1,1.1-2,1.4s-1.8,0.5-3.1,0.5h-4.8V150z M218.8,164.5h3.3
|
||||
c0.8,0,1.5-0.1,2.2-0.3c0.6-0.2,1.2-0.5,1.6-0.9c0.4-0.4,0.8-1,1-1.8c0.2-0.7,0.3-1.6,0.3-2.8V157c0-1.1-0.1-2-0.3-2.7
|
||||
c-0.2-0.7-0.5-1.3-0.9-1.8c-0.4-0.4-0.9-0.8-1.6-1c-0.6-0.2-1.4-0.3-2.2-0.3h-3.4V164.5z"/>
|
||||
<path class="st14" d="M237.9,155.6c-0.2,0-0.4-0.1-0.7-0.1c-0.2,0-0.4,0-0.6,0c-1.1,0-1.9,0.3-2.4,1c-0.5,0.7-0.8,1.7-0.8,3.2v6.1
|
||||
H232v-11.2h1.1l0.2,1.8c0.7-1.3,1.9-1.9,3.5-1.9c0.2,0,0.5,0,0.7,0.1c0.2,0,0.4,0.1,0.6,0.1L237.9,155.6z"/>
|
||||
<path class="st14" d="M244.3,154.2c1,0,1.7,0.1,2.4,0.4c0.6,0.2,1.1,0.6,1.5,1.1c0.4,0.5,0.6,1,0.8,1.7c0.2,0.7,0.2,1.4,0.2,2.2
|
||||
v1.2c0,0.8-0.1,1.5-0.3,2.2c-0.2,0.7-0.5,1.2-0.8,1.7c-0.4,0.5-0.9,0.8-1.5,1.1c-0.6,0.2-1.4,0.4-2.3,0.4c-1,0-1.7-0.1-2.4-0.4
|
||||
c-0.6-0.2-1.1-0.6-1.5-1.1s-0.6-1-0.8-1.7c-0.2-0.7-0.2-1.4-0.2-2.2v-1.2c0-0.8,0.1-1.5,0.3-2.2c0.2-0.7,0.5-1.2,0.9-1.7
|
||||
s0.9-0.8,1.5-1.1C242.7,154.3,243.4,154.2,244.3,154.2z M244.3,164.8c0.7,0,1.2-0.1,1.7-0.2s0.8-0.4,1.1-0.7
|
||||
c0.3-0.3,0.5-0.8,0.6-1.3c0.1-0.5,0.2-1.2,0.2-1.9v-1c0-0.8-0.1-1.4-0.2-2s-0.3-1-0.6-1.3c-0.3-0.3-0.6-0.6-1.1-0.7s-1-0.2-1.6-0.2
|
||||
c-0.7,0-1.2,0.1-1.7,0.2c-0.5,0.2-0.8,0.4-1.1,0.7c-0.3,0.3-0.5,0.8-0.6,1.3c-0.1,0.5-0.2,1.2-0.2,1.9v1c0,0.8,0.1,1.4,0.2,1.9
|
||||
c0.1,0.5,0.3,1,0.6,1.3c0.3,0.3,0.6,0.6,1.1,0.7C243.1,164.7,243.7,164.8,244.3,164.8z"/>
|
||||
<path class="st14" d="M261.9,160.6c0,0.9-0.1,1.7-0.4,2.4c-0.2,0.7-0.6,1.2-1,1.7s-0.9,0.8-1.5,1s-1.2,0.3-1.9,0.3
|
||||
c-0.4,0-0.7,0-1,0c-0.3,0-0.6-0.1-0.8-0.1c-0.3-0.1-0.5-0.2-0.8-0.3c-0.3-0.1-0.5-0.2-0.8-0.4v5.7h-1.3v-16.3h1.1l0.2,1.5
|
||||
c0.8-1.2,2.1-1.8,3.9-1.8c0.6,0,1.2,0.1,1.8,0.3c0.5,0.2,1,0.5,1.4,0.9c0.4,0.4,0.7,1,0.9,1.7c0.2,0.7,0.3,1.5,0.3,2.5V160.6z
|
||||
M260.5,159.9c0-0.7,0-1.3-0.1-1.9s-0.3-1-0.5-1.4c-0.3-0.4-0.6-0.7-1-0.9c-0.4-0.2-1-0.3-1.6-0.3c-0.7,0-1.2,0.1-1.7,0.3
|
||||
c-0.4,0.2-0.8,0.4-1.1,0.7s-0.5,0.7-0.6,1.2c-0.1,0.5-0.2,1-0.2,1.7v4.7c0.5,0.3,1,0.5,1.5,0.6c0.5,0.1,1,0.2,1.7,0.2
|
||||
c0.7,0,1.3-0.1,1.7-0.3s0.8-0.5,1.1-0.8c0.3-0.4,0.5-0.8,0.6-1.4s0.2-1.2,0.2-1.9V159.9z"/>
|
||||
<path class="st14" d="M269.4,165.9c-0.7,0-1.5-0.1-2.2-0.3c-0.7-0.2-1.4-0.5-2.1-0.8v-15.5h1.3v6.6c0.4-0.6,0.9-1.1,1.5-1.3
|
||||
c0.6-0.3,1.3-0.4,2.2-0.4c0.7,0,1.3,0.1,1.8,0.3c0.6,0.2,1,0.5,1.4,0.9s0.7,1,0.9,1.6c0.2,0.7,0.3,1.5,0.3,2.5v1
|
||||
c0,1.8-0.4,3.2-1.3,4.1C272.4,165.5,271.1,165.9,269.4,165.9z M269.3,164.8c0.7,0,1.3-0.1,1.8-0.3c0.5-0.2,0.9-0.4,1.2-0.8
|
||||
c0.3-0.4,0.5-0.8,0.7-1.4c0.1-0.6,0.2-1.2,0.2-2v-0.5c0-0.7-0.1-1.3-0.2-1.9c-0.1-0.6-0.3-1-0.5-1.4s-0.6-0.7-1-0.9
|
||||
c-0.4-0.2-1-0.3-1.6-0.3c-0.5,0-1,0.1-1.4,0.2s-0.8,0.4-1.1,0.7c-0.3,0.3-0.5,0.7-0.7,1.2c-0.2,0.5-0.3,1.1-0.3,1.8v4.9
|
||||
c0.4,0.2,0.9,0.4,1.3,0.5C268.2,164.7,268.7,164.8,269.3,164.8z"/>
|
||||
<path class="st14" d="M282.3,154.2c1,0,1.7,0.1,2.4,0.4c0.6,0.2,1.1,0.6,1.5,1.1c0.4,0.5,0.6,1,0.8,1.7c0.2,0.7,0.2,1.4,0.2,2.2
|
||||
v1.2c0,0.8-0.1,1.5-0.3,2.2c-0.2,0.7-0.5,1.2-0.8,1.7c-0.4,0.5-0.9,0.8-1.5,1.1c-0.6,0.2-1.4,0.4-2.3,0.4c-1,0-1.7-0.1-2.4-0.4
|
||||
c-0.6-0.2-1.1-0.6-1.5-1.1s-0.6-1-0.8-1.7c-0.2-0.7-0.2-1.4-0.2-2.2v-1.2c0-0.8,0.1-1.5,0.3-2.2c0.2-0.7,0.5-1.2,0.9-1.7
|
||||
s0.9-0.8,1.5-1.1C280.6,154.3,281.4,154.2,282.3,154.2z M282.3,164.8c0.7,0,1.2-0.1,1.7-0.2s0.8-0.4,1.1-0.7
|
||||
c0.3-0.3,0.5-0.8,0.6-1.3c0.1-0.5,0.2-1.2,0.2-1.9v-1c0-0.8-0.1-1.4-0.2-2s-0.3-1-0.6-1.3c-0.3-0.3-0.6-0.6-1.1-0.7s-1-0.2-1.6-0.2
|
||||
c-0.7,0-1.2,0.1-1.7,0.2c-0.5,0.2-0.8,0.4-1.1,0.7c-0.3,0.3-0.5,0.8-0.6,1.3c-0.1,0.5-0.2,1.2-0.2,1.9v1c0,0.8,0.1,1.4,0.2,1.9
|
||||
c0.1,0.5,0.3,1,0.6,1.3c0.3,0.3,0.6,0.6,1.1,0.7C281.1,164.7,281.6,164.8,282.3,164.8z"/>
|
||||
<path class="st14" d="M288.8,154.4h1.5l3.1,4.4l3.1-4.4h1.5l-3.9,5.4l4.2,5.8h-1.6l-3.4-4.9l-3.4,4.9h-1.5l4.2-5.9L288.8,154.4z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st14" d="M379.5,166c-1.1,0-2-0.1-2.8-0.4s-1.3-0.7-1.7-1.2c-0.4-0.6-0.7-1.2-0.9-2c-0.2-0.8-0.2-1.8-0.2-2.8V150h1.4
|
||||
v9.5c0,1,0.1,1.9,0.2,2.5c0.2,0.7,0.4,1.2,0.7,1.6c0.3,0.4,0.8,0.7,1.3,0.9c0.5,0.2,1.2,0.3,2,0.3c0.8,0,1.5-0.1,2-0.3
|
||||
c0.5-0.2,1-0.5,1.3-0.9c0.3-0.4,0.6-1,0.7-1.6s0.2-1.5,0.2-2.5V150h1.4v9.5c0,1.1-0.1,2-0.3,2.8s-0.5,1.5-0.9,2
|
||||
c-0.4,0.5-1,0.9-1.7,1.2S380.6,166,379.5,166z"/>
|
||||
<path class="st14" d="M394.4,157.1c0.7,0.1,1.3,0.3,1.8,0.5c0.5,0.2,0.9,0.5,1.2,0.9s0.5,0.8,0.6,1.2c0.1,0.5,0.2,0.9,0.2,1.5v0.3
|
||||
c0,0.6-0.1,1.2-0.3,1.8c-0.2,0.5-0.6,1-1,1.4c-0.5,0.4-1,0.7-1.8,0.9c-0.7,0.2-1.5,0.3-2.5,0.3c-0.8,0-1.6-0.1-2.4-0.2
|
||||
c-0.8-0.1-1.4-0.3-2-0.5l0.3-1.2c0.6,0.2,1.2,0.3,1.9,0.4c0.7,0.1,1.4,0.2,2.2,0.2c1.5,0,2.6-0.3,3.2-0.8c0.6-0.5,1-1.4,1-2.5
|
||||
c0-0.4,0-0.7-0.1-1c-0.1-0.3-0.2-0.6-0.4-0.9c-0.2-0.3-0.5-0.5-0.9-0.6c-0.4-0.2-0.9-0.3-1.4-0.4l-2-0.3c-1.3-0.2-2.3-0.6-2.8-1.3
|
||||
c-0.6-0.7-0.8-1.6-0.8-2.7V154c0-0.7,0.1-1.3,0.4-1.8c0.3-0.5,0.6-1,1.1-1.3c0.5-0.4,1.1-0.6,1.8-0.8c0.7-0.2,1.5-0.3,2.3-0.3
|
||||
c0.7,0,1.5,0.1,2.1,0.2c0.7,0.1,1.2,0.3,1.7,0.5l-0.3,1.1c-0.5-0.2-1.1-0.3-1.7-0.4s-1.3-0.2-2-0.2c-1.5,0-2.5,0.3-3.2,0.8
|
||||
c-0.6,0.5-1,1.3-1,2.3c0,0.8,0.2,1.4,0.6,1.8c0.4,0.4,1.1,0.7,2.2,0.8L394.4,157.1z"/>
|
||||
<path class="st14" d="M401.4,165.7V150h5.5c0.8,0,1.5,0.1,2,0.3c0.5,0.2,1,0.5,1.3,0.8c0.3,0.3,0.6,0.7,0.7,1.2
|
||||
c0.1,0.4,0.2,0.9,0.2,1.4v0.5c0,0.8-0.2,1.5-0.6,2c-0.4,0.5-0.9,0.9-1.6,1.2c0.5,0.1,0.8,0.3,1.2,0.5c0.3,0.2,0.6,0.5,0.8,0.9
|
||||
c0.2,0.3,0.4,0.7,0.5,1.1c0.1,0.4,0.2,0.8,0.2,1.3v0.5c0,0.6-0.1,1.1-0.3,1.6c-0.2,0.5-0.5,0.9-0.9,1.3c-0.4,0.4-0.9,0.6-1.5,0.8
|
||||
s-1.3,0.3-2.1,0.3H401.4z M402.8,156.9h4.2c0.9,0,1.7-0.2,2.2-0.7c0.5-0.4,0.7-1.1,0.7-1.8v-0.5c0-1.8-1-2.8-3.1-2.8h-3.9V156.9z
|
||||
M402.8,164.5h4.2c1.1,0,1.9-0.2,2.4-0.7c0.5-0.4,0.8-1.2,0.8-2.2v-0.5c0-2-1.1-3.1-3.3-3.1h-4.2V164.5z"/>
|
||||
<path class="st14" d="M421.6,150v7.1l7-7.1h1.6l-7.5,7.5l8,8.1h-1.8l-7.3-7.5v7.5h-1.3V150H421.6z"/>
|
||||
<path class="st14" d="M433.1,160.5c0,0.8,0.1,1.4,0.2,2c0.1,0.5,0.4,1,0.7,1.3c0.3,0.3,0.8,0.6,1.3,0.7c0.5,0.2,1.2,0.2,2.1,0.2
|
||||
c0.5,0,0.9,0,1.5-0.1c0.5-0.1,1-0.1,1.3-0.2l-0.2,1.1c-0.3,0.1-0.8,0.2-1.3,0.3c-0.5,0.1-1.1,0.1-1.6,0.1c-1,0-1.8-0.1-2.5-0.3
|
||||
c-0.7-0.2-1.2-0.6-1.7-1s-0.7-1-0.9-1.7c-0.2-0.7-0.3-1.5-0.3-2.4v-0.9c0-0.8,0.1-1.6,0.3-2.3c0.2-0.7,0.5-1.3,0.8-1.7
|
||||
c0.4-0.5,0.9-0.9,1.5-1.1c0.6-0.3,1.3-0.4,2.2-0.4c0.7,0,1.4,0.1,1.9,0.3c0.5,0.2,1,0.5,1.3,0.9s0.6,0.9,0.8,1.4
|
||||
c0.2,0.5,0.2,1.2,0.2,1.8v0.6c0,0.4-0.1,0.7-0.2,0.9c-0.1,0.2-0.4,0.3-0.8,0.3H433.1z M436.4,155.3c-0.6,0-1,0.1-1.5,0.2
|
||||
s-0.8,0.4-1,0.7s-0.5,0.8-0.6,1.3c-0.1,0.5-0.2,1.2-0.2,2h6.5v-0.8c0-1.1-0.2-2-0.7-2.6S437.5,155.3,436.4,155.3z"/>
|
||||
<path class="st14" d="M451.7,154.4h1.5l-4.9,12.6c-0.3,0.8-0.6,1.4-0.9,1.9c-0.3,0.5-0.6,0.9-0.9,1.2c-0.3,0.3-0.6,0.5-1,0.6
|
||||
c-0.4,0.1-0.7,0.2-1.2,0.2c-0.3,0-0.6,0-0.9-0.1c-0.3-0.1-0.5-0.1-0.8-0.2l0.2-1c0.2,0,0.4,0.1,0.6,0.1c0.2,0,0.5,0,0.7,0
|
||||
c0.3,0,0.6,0,0.9-0.1c0.3-0.1,0.5-0.2,0.7-0.4c0.2-0.2,0.4-0.5,0.6-0.8c0.2-0.4,0.4-0.9,0.6-1.5l0.4-1.2l-4.8-11.4h1.5l3.9,9.7
|
||||
L451.7,154.4z"/>
|
||||
</g>
|
||||
</svg>
|
||||
<hr>
|
||||
|
||||
<h3>What happens if I lose my passphrase?</h3>
|
||||
<p>Your passphrase is used to encrypt your private keys. If you lose your passphrase, you will no longer be able to decrypt your private key file nor have access to the contents of your Wallet or My Purchases.</p>
|
||||
<p>In order to guarantee your privacy, nobody can help you recover your passphrase, including High Fidelity.
|
||||
|
||||
<p><b>Please write it down and store it securely.</b></p>
|
||||
<p> </p>
|
||||
<hr>
|
||||
|
||||
<h2>Want to learn more?</h2>
|
||||
<p>You can find out much more about the blockchain and about commerce in High Fidelity by visiting our Docs site:</p>
|
||||
<p><a href="http://docs.highfidelity.com" class="btn">Visit High Fidelity's Docs</a></p>
|
||||
<hr>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
High Fidelity | <a href="http://highfidelity.com" target="_blank">highfidelity.com</a>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Before Width: | Height: | Size: 312 KiB After Width: | Height: | Size: 604 KiB |
Before Width: | Height: | Size: 232 KiB After Width: | Height: | Size: 503 KiB |
Before Width: | Height: | Size: 307 KiB After Width: | Height: | Size: 585 KiB |
Before Width: | Height: | Size: 268 KiB After Width: | Height: | Size: 547 KiB |
|
@ -14,11 +14,17 @@
|
|||
var isWindowFocused = true;
|
||||
var isKeyboardRaised = false;
|
||||
var isNumericKeyboard = false;
|
||||
var isPasswordField = false;
|
||||
|
||||
function shouldSetPasswordField() {
|
||||
var nodeType = document.activeElement.type;
|
||||
return nodeType === "password";
|
||||
}
|
||||
|
||||
function shouldRaiseKeyboard() {
|
||||
var nodeName = document.activeElement.nodeName;
|
||||
var nodeType = document.activeElement.type;
|
||||
if (nodeName === "INPUT" && ["email", "number", "password", "tel", "text", "url"].indexOf(nodeType) !== -1
|
||||
if (nodeName === "INPUT" && ["email", "number", "password", "tel", "text", "url", "search"].indexOf(nodeType) !== -1
|
||||
|| document.activeElement.nodeName === "TEXTAREA") {
|
||||
return true;
|
||||
} else {
|
||||
|
@ -53,12 +59,14 @@
|
|||
setInterval(function () {
|
||||
var keyboardRaised = shouldRaiseKeyboard();
|
||||
var numericKeyboard = shouldSetNumeric();
|
||||
var passwordField = shouldSetPasswordField();
|
||||
|
||||
if (isWindowFocused && (keyboardRaised !== isKeyboardRaised || numericKeyboard !== isNumericKeyboard)) {
|
||||
if (isWindowFocused &&
|
||||
(keyboardRaised !== isKeyboardRaised || numericKeyboard !== isNumericKeyboard || passwordField !== isPasswordField)) {
|
||||
|
||||
if (typeof EventBridge !== "undefined" && EventBridge !== null) {
|
||||
EventBridge.emitWebEvent(
|
||||
keyboardRaised ? ("_RAISE_KEYBOARD" + (numericKeyboard ? "_NUMERIC" : "")) : "_LOWER_KEYBOARD"
|
||||
keyboardRaised ? ("_RAISE_KEYBOARD" + (numericKeyboard ? "_NUMERIC" : "") + (passwordField ? "_PASSWORD" : "")) : "_LOWER_KEYBOARD"
|
||||
);
|
||||
} else {
|
||||
if (numWarnings < MAX_WARNINGS) {
|
||||
|
@ -74,6 +82,7 @@
|
|||
|
||||
isKeyboardRaised = keyboardRaised;
|
||||
isNumericKeyboard = numericKeyboard;
|
||||
isPasswordField = passwordField;
|
||||
}
|
||||
}, POLL_FREQUENCY);
|
||||
|
||||
|
|
|
@ -2,14 +2,14 @@ name = mannequin
|
|||
type = body+head
|
||||
scale = 1
|
||||
filename = mannequin/mannequin.baked.fbx
|
||||
joint = jointEyeLeft = LeftEye
|
||||
joint = jointRightHand = RightHand
|
||||
joint = jointHead = Head
|
||||
joint = jointEyeRight = RightEye
|
||||
joint = jointLean = Spine
|
||||
joint = jointNeck = Neck
|
||||
joint = jointLeftHand = LeftHand
|
||||
joint = jointRoot = Hips
|
||||
joint = jointLean = Spine
|
||||
joint = jointLeftHand = LeftHand
|
||||
joint = jointHead = Head
|
||||
joint = jointEyeLeft = LeftEye
|
||||
joint = jointEyeRight = RightEye
|
||||
joint = jointRightHand = RightHand
|
||||
joint = jointNeck = Neck
|
||||
freeJoint = LeftArm
|
||||
freeJoint = LeftForeArm
|
||||
freeJoint = RightArm
|
||||
|
@ -18,72 +18,72 @@ bs = EyeBlink_L = blink = 1
|
|||
bs = JawOpen = mouth_Open = 1
|
||||
bs = LipsFunnel = Oo = 1
|
||||
bs = BrowsU_L = brow_Up = 1
|
||||
jointIndex = RightHandIndex2 = 27
|
||||
jointIndex = LeftHandIndex2 = 51
|
||||
jointIndex = RightUpLeg = 6
|
||||
jointIndex = RightToe_End = 10
|
||||
jointIndex = RightEye = 65
|
||||
jointIndex = LeftHandPinky1 = 42
|
||||
jointIndex = RightHandRing1 = 22
|
||||
jointIndex = face = 67
|
||||
jointIndex = LeftUpLeg = 1
|
||||
jointIndex = LeftHand = 41
|
||||
jointIndex = LeftHandMiddle1 = 58
|
||||
jointIndex = LeftHandIndex1 = 50
|
||||
jointIndex = LeftEye = 64
|
||||
jointIndex = RightHandIndex1 = 26
|
||||
jointIndex = LeftHandPinky4 = 45
|
||||
jointIndex = RightArm = 15
|
||||
jointIndex = LeftShoulder = 38
|
||||
jointIndex = RightHandPinky2 = 19
|
||||
jointIndex = RightHandThumb1 = 30
|
||||
jointIndex = RightForeArm = 16
|
||||
jointIndex = LeftHandMiddle3 = 60
|
||||
jointIndex = Neck = 62
|
||||
jointIndex = LeftHandThumb1 = 54
|
||||
jointIndex = RightHandMiddle2 = 35
|
||||
jointIndex = LeftHandMiddle4 = 61
|
||||
jointIndex = mannequin = 68
|
||||
jointIndex = Spine1 = 12
|
||||
jointIndex = LeftHand = 41
|
||||
jointIndex = LeftHandRing4 = 49
|
||||
jointIndex = RightHandMiddle3 = 36
|
||||
jointIndex = LeftHandThumb4 = 57
|
||||
jointIndex = RightToe_End = 10
|
||||
jointIndex = LeftHandRing1 = 46
|
||||
jointIndex = LeftForeArm = 40
|
||||
jointIndex = RightHandIndex4 = 29
|
||||
jointIndex = LeftShoulder = 38
|
||||
jointIndex = RightHandMiddle4 = 37
|
||||
jointIndex = RightShoulder = 14
|
||||
jointIndex = LeftLeg = 2
|
||||
jointIndex = LeftToe_End = 5
|
||||
jointIndex = Hips = 0
|
||||
jointIndex = RightFoot = 8
|
||||
jointIndex = RightHandThumb2 = 31
|
||||
jointIndex = LeftHandMiddle3 = 60
|
||||
jointIndex = RightHandThumb1 = 30
|
||||
jointIndex = Neck = 62
|
||||
jointIndex = Spine = 11
|
||||
jointIndex = RightHandThumb4 = 33
|
||||
jointIndex = RightHandMiddle1 = 34
|
||||
jointIndex = LeftHandIndex4 = 53
|
||||
jointIndex = face = 68
|
||||
jointIndex = RightHandRing3 = 24
|
||||
jointIndex = LeftHandPinky4 = 45
|
||||
jointIndex = LeftHandMiddle2 = 59
|
||||
jointIndex = RightHandThumb3 = 32
|
||||
jointIndex = LeftHandPinky3 = 44
|
||||
jointIndex = HeadTop_End = 66
|
||||
jointIndex = Spine1 = 12
|
||||
jointIndex = LeftHandRing3 = 48
|
||||
jointIndex = mannequin1 = 67
|
||||
jointIndex = RightEye = 65
|
||||
jointIndex = RightHandRing4 = 25
|
||||
jointIndex = RightHandPinky4 = 21
|
||||
jointIndex = LeftHandRing2 = 47
|
||||
jointIndex = RightHandIndex3 = 28
|
||||
jointIndex = RightUpLeg = 6
|
||||
jointIndex = LeftArm = 39
|
||||
jointIndex = LeftHandThumb3 = 56
|
||||
jointIndex = RightHandIndex2 = 27
|
||||
jointIndex = RightForeArm = 16
|
||||
jointIndex = RightArm = 15
|
||||
jointIndex = RightHandRing2 = 23
|
||||
jointIndex = LeftHandMiddle1 = 58
|
||||
jointIndex = Spine2 = 13
|
||||
jointIndex = LeftHandThumb2 = 55
|
||||
jointIndex = RightHandMiddle2 = 35
|
||||
jointIndex = RightHandPinky1 = 18
|
||||
jointIndex = LeftUpLeg = 1
|
||||
jointIndex = RightLeg = 7
|
||||
jointIndex = LeftHandIndex2 = 51
|
||||
jointIndex = RightHand = 17
|
||||
jointIndex = LeftHandIndex3 = 52
|
||||
jointIndex = RightHandIndex3 = 28
|
||||
jointIndex = RightHandMiddle4 = 37
|
||||
jointIndex = LeftLeg = 2
|
||||
jointIndex = RightHandMiddle1 = 34
|
||||
jointIndex = Spine2 = 13
|
||||
jointIndex = LeftHandMiddle2 = 59
|
||||
jointIndex = LeftHandPinky3 = 44
|
||||
jointIndex = LeftHandThumb3 = 56
|
||||
jointIndex = LeftHandRing4 = 49
|
||||
jointIndex = RightHandThumb2 = 31
|
||||
jointIndex = LeftHandRing3 = 48
|
||||
jointIndex = HeadTop_End = 66
|
||||
jointIndex = LeftHandThumb4 = 57
|
||||
jointIndex = RightHandThumb3 = 32
|
||||
jointIndex = RightHandPinky1 = 18
|
||||
jointIndex = RightLeg = 7
|
||||
jointIndex = RightHandMiddle3 = 36
|
||||
jointIndex = RightHandPinky3 = 20
|
||||
jointIndex = LeftToeBase = 4
|
||||
jointIndex = LeftForeArm = 40
|
||||
jointIndex = RightShoulder = 14
|
||||
jointIndex = LeftHandRing2 = 47
|
||||
jointIndex = LeftHandThumb2 = 55
|
||||
jointIndex = Head = 63
|
||||
jointIndex = RightHandRing4 = 25
|
||||
jointIndex = LeftHandRing1 = 46
|
||||
jointIndex = LeftFoot = 3
|
||||
jointIndex = RightHandRing3 = 24
|
||||
jointIndex = RightHandThumb4 = 33
|
||||
jointIndex = LeftArm = 39
|
||||
jointIndex = LeftToe_End = 5
|
||||
jointIndex = RightHandPinky3 = 20
|
||||
jointIndex = RightHandIndex1 = 26
|
||||
jointIndex = LeftHandPinky1 = 42
|
||||
jointIndex = RightToeBase = 9
|
||||
jointIndex = RightHandPinky4 = 21
|
||||
jointIndex = Spine = 11
|
||||
jointIndex = LeftHandIndex4 = 53
|
||||
jointIndex = LeftHandIndex1 = 50
|
||||
jointIndex = LeftToeBase = 4
|
||||
jointIndex = LeftHandPinky2 = 43
|
||||
jointIndex = RightHandIndex4 = 29
|
||||
jointIndex = Hips = 0
|
||||
jointIndex = RightHandRing2 = 23
|
||||
jointIndex = RightHandRing1 = 22
|
||||
jointIndex = LeftHandThumb1 = 54
|
||||
jointIndex = LeftEye = 64
|
||||
jointIndex = Head = 63
|
||||
|
|
BIN
interface/resources/meshes/mannequin/Eyes.ktx
Executable file → Normal file
BIN
interface/resources/meshes/mannequin/lambert1_Base_Color.ktx
Executable file → Normal file
BIN
interface/resources/meshes/mannequin/lambert1_Normal_OpenGL.ktx
Executable file → Normal file
BIN
interface/resources/meshes/mannequin/lambert1_Roughness.ktx
Executable file → Normal file
BIN
interface/resources/meshes/mannequin/mannequin.baked.fbx
Executable file → Normal file
|
@ -87,7 +87,7 @@ Window {
|
|||
onReceivedHifiSchemeURL: resetAfterTeleport();
|
||||
|
||||
// Update location after using back and forward buttons.
|
||||
onMetaverseServerUrlChanged: updateLocationTextTimer.start();
|
||||
onHostChanged: updateLocationTextTimer.start();
|
||||
|
||||
ListModel { id: suggestions }
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ import "./hifi/audio" as HifiAudio
|
|||
Hifi.AvatarInputs {
|
||||
id: root;
|
||||
objectName: "AvatarInputs"
|
||||
property int modality: Qt.NonModal
|
||||
width: audio.width;
|
||||
height: audio.height;
|
||||
x: 10; y: 5;
|
||||
|
|
|
@ -119,6 +119,7 @@ Item {
|
|||
width: parent.width
|
||||
focus: true
|
||||
label: "Username or Email"
|
||||
activeFocusOnPress: true
|
||||
|
||||
ShortcutText {
|
||||
anchors {
|
||||
|
@ -135,6 +136,9 @@ Item {
|
|||
|
||||
onLinkActivated: loginDialog.openUrl(link)
|
||||
}
|
||||
onFocusChanged: {
|
||||
root.text = "";
|
||||
}
|
||||
}
|
||||
|
||||
TextField {
|
||||
|
@ -143,6 +147,7 @@ Item {
|
|||
|
||||
label: "Password"
|
||||
echoMode: showPassword.checked ? TextInput.Normal : TextInput.Password
|
||||
activeFocusOnPress: true
|
||||
|
||||
ShortcutText {
|
||||
anchors {
|
||||
|
@ -159,6 +164,10 @@ Item {
|
|||
|
||||
onLinkActivated: loginDialog.openUrl(link)
|
||||
}
|
||||
onFocusChanged: {
|
||||
root.text = "";
|
||||
root.isPassword = true;
|
||||
}
|
||||
}
|
||||
|
||||
CheckBoxQQC2 {
|
||||
|
@ -233,18 +242,6 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
// Override ScrollingWindow's keyboard that would be at very bottom of dialog.
|
||||
Keyboard {
|
||||
raised: keyboardEnabled && keyboardRaised
|
||||
numeric: punctuationMode
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
bottomMargin: keyboardRaised ? 2 * hifi.dimensions.contentSpacing.y : 0
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
root.title = qsTr("Sign Into High Fidelity")
|
||||
root.iconText = "<"
|
||||
|
|
|
@ -108,12 +108,17 @@ Item {
|
|||
id: emailField
|
||||
width: parent.width
|
||||
label: "Email"
|
||||
activeFocusOnPress: true
|
||||
onFocusChanged: {
|
||||
root.text = "";
|
||||
}
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: usernameField
|
||||
width: parent.width
|
||||
label: "Username"
|
||||
activeFocusOnPress: true
|
||||
|
||||
ShortcutText {
|
||||
anchors {
|
||||
|
@ -128,6 +133,9 @@ Item {
|
|||
horizontalAlignment: Text.AlignHCenter
|
||||
|
||||
color: hifi.colors.blueAccent
|
||||
onFocusChanged: {
|
||||
root.text = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,6 +144,7 @@ Item {
|
|||
width: parent.width
|
||||
label: "Password"
|
||||
echoMode: TextInput.Password
|
||||
activeFocusOnPress: true
|
||||
|
||||
ShortcutText {
|
||||
anchors {
|
||||
|
@ -151,6 +160,11 @@ Item {
|
|||
|
||||
color: hifi.colors.blueAccent
|
||||
}
|
||||
|
||||
onFocusChanged: {
|
||||
root.text = "";
|
||||
root.isPassword = focus
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
|
@ -202,18 +216,6 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
// Override ScrollingWindow's keyboard that would be at very bottom of dialog.
|
||||
Keyboard {
|
||||
raised: keyboardEnabled && keyboardRaised
|
||||
numeric: punctuationMode
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
bottomMargin: keyboardRaised ? 2 * hifi.dimensions.contentSpacing.y : 0
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
root.title = qsTr("Create an Account")
|
||||
root.iconText = "<"
|
||||
|
|
|
@ -8,6 +8,9 @@ Item {
|
|||
|
||||
anchors.leftMargin: 300
|
||||
objectName: "StatsItem"
|
||||
property int modality: Qt.NonModal
|
||||
implicitHeight: row.height
|
||||
implicitWidth: row.width
|
||||
|
||||
Component.onCompleted: {
|
||||
stats.parentChanged.connect(fill);
|
||||
|
@ -18,8 +21,9 @@ Item {
|
|||
}
|
||||
|
||||
function fill() {
|
||||
// Explicitly fill in order to avoid warnings at shutdown
|
||||
anchors.fill = parent;
|
||||
// This will cause a warning at shutdown, need to find another way to remove
|
||||
// the warning other than filling the anchors to the parent
|
||||
anchors.horizontalCenter = parent.horizontalCenter
|
||||
}
|
||||
|
||||
Hifi.Stats {
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4 as Original
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import TabletScriptingInterface 1.0
|
||||
|
||||
import "../styles-uit"
|
||||
|
||||
|
@ -26,6 +27,16 @@ Original.Button {
|
|||
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
onHoveredChanged: {
|
||||
if (hovered) {
|
||||
tabletInterface.playSound(TabletEnums.ButtonHover);
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
tabletInterface.playSound(TabletEnums.ButtonClick);
|
||||
}
|
||||
|
||||
style: ButtonStyle {
|
||||
|
||||
background: Rectangle {
|
||||
|
|
|
@ -14,6 +14,8 @@ import QtQuick.Controls.Styles 1.4
|
|||
|
||||
import "../styles-uit"
|
||||
|
||||
import TabletScriptingInterface 1.0
|
||||
|
||||
Original.CheckBox {
|
||||
id: checkBox
|
||||
|
||||
|
@ -28,6 +30,15 @@ Original.CheckBox {
|
|||
readonly property int checkRadius: 2
|
||||
activeFocusOnPress: true
|
||||
|
||||
onClicked: {
|
||||
tabletInterface.playSound(TabletEnums.ButtonClick);
|
||||
}
|
||||
|
||||
// TODO: doesnt works for QQC1. check with QQC2
|
||||
// onHovered: {
|
||||
// tabletInterface.playSound(TabletEnums.ButtonHover);
|
||||
// }
|
||||
|
||||
style: CheckBoxStyle {
|
||||
indicator: Rectangle {
|
||||
id: box
|
||||
|
|
|
@ -13,6 +13,7 @@ import QtQuick.Controls 2.2
|
|||
|
||||
import "../styles-uit"
|
||||
import "../controls-uit" as HiFiControls
|
||||
import TabletScriptingInterface 1.0
|
||||
|
||||
CheckBox {
|
||||
id: checkBox
|
||||
|
@ -32,6 +33,17 @@ CheckBox {
|
|||
readonly property int checkSize: Math.max(boxSize - 8, 10)
|
||||
readonly property int checkRadius: isRound ? checkSize / 2 : 2
|
||||
focusPolicy: Qt.ClickFocus
|
||||
hoverEnabled: true
|
||||
|
||||
onClicked: {
|
||||
tabletInterface.playSound(TabletEnums.ButtonClick);
|
||||
}
|
||||
|
||||
onHoveredChanged: {
|
||||
if (hovered) {
|
||||
tabletInterface.playSound(TabletEnums.ButtonHover);
|
||||
}
|
||||
}
|
||||
|
||||
indicator: Rectangle {
|
||||
id: box
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4 as Original
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import TabletScriptingInterface 1.0
|
||||
|
||||
import "../styles-uit"
|
||||
|
||||
|
@ -24,6 +25,16 @@ Original.Button {
|
|||
width: 120
|
||||
height: 28
|
||||
|
||||
onHoveredChanged: {
|
||||
if (hovered) {
|
||||
tabletInterface.playSound(TabletEnums.ButtonHover);
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
tabletInterface.playSound(TabletEnums.ButtonClick);
|
||||
}
|
||||
|
||||
style: ButtonStyle {
|
||||
|
||||
background: Rectangle {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import QtQuick 2.0
|
||||
import TabletScriptingInterface 1.0
|
||||
|
||||
Item {
|
||||
id: keyItem
|
||||
|
@ -32,8 +33,15 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
onContainsMouseChanged: {
|
||||
if (containsMouse) {
|
||||
tabletInterface.playSound(TabletEnums.ButtonHover);
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
mouse.accepted = true;
|
||||
tabletInterface.playSound(TabletEnums.ButtonClick);
|
||||
|
||||
webEntity.synthesizeKeyPress(glyph);
|
||||
webEntity.synthesizeKeyPress(glyph, mirrorText);
|
||||
|
@ -47,8 +55,21 @@ Item {
|
|||
mouse.accepted = true;
|
||||
}
|
||||
|
||||
property var _HAPTIC_STRENGTH: 0.1;
|
||||
property var _HAPTIC_DURATION: 3.0;
|
||||
property var leftHand: 0;
|
||||
property var rightHand: 1;
|
||||
|
||||
onEntered: {
|
||||
keyItem.state = "mouseOver";
|
||||
|
||||
var globalPosition = keyItem.mapToGlobal(mouseArea1.mouseX, mouseArea1.mouseY);
|
||||
var deviceId = Web3DOverlay.deviceIdByTouchPoint(globalPosition.x, globalPosition.y);
|
||||
var hand = deviceId - 1; // based on touchEventUtils.js, deviceId is 'hand + 1', so 'hand' is 'deviceId' - 1
|
||||
|
||||
if (hand == leftHand || hand == rightHand) {
|
||||
Controller.triggerHapticPulse(_HAPTIC_STRENGTH, _HAPTIC_DURATION, hand);
|
||||
}
|
||||
}
|
||||
|
||||
onExited: {
|
||||
|
|
|
@ -13,6 +13,7 @@ import "."
|
|||
|
||||
Rectangle {
|
||||
id: keyboardBase
|
||||
objectName: "keyboard"
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
@ -27,6 +28,8 @@ Rectangle {
|
|||
|
||||
readonly property int mirrorTextHeight: keyboardRowHeight
|
||||
|
||||
property bool password: false
|
||||
property alias mirroredText: mirrorText.text
|
||||
property bool showMirrorText: true
|
||||
readonly property int raisedHeight: 200
|
||||
|
||||
|
@ -36,6 +39,10 @@ Rectangle {
|
|||
property bool shiftMode: false
|
||||
property bool numericShiftMode: false
|
||||
|
||||
onRaisedChanged: {
|
||||
mirroredText = "";
|
||||
}
|
||||
|
||||
function resetShiftMode(mode) {
|
||||
shiftMode = mode;
|
||||
shiftKey.resetToggledMode(mode);
|
||||
|
@ -112,19 +119,23 @@ Rectangle {
|
|||
color: "#252525"
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
TextEdit {
|
||||
TextInput {
|
||||
id: mirrorText
|
||||
visible: showMirrorText
|
||||
size: 13.5
|
||||
FontLoader { id: ralewaySemiBold; source: "../../fonts/Raleway-SemiBold.ttf"; }
|
||||
font.family: ralewaySemiBold.name
|
||||
font.pointSize: 13.5
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
color: "#FFFFFF";
|
||||
anchors.fill: parent
|
||||
wrapMode: Text.WordWrap
|
||||
readOnly: false // we need to leave this property read-only to allow control to accept QKeyEvent
|
||||
readOnly: false // we need this to allow control to accept QKeyEvent
|
||||
selectByMouse: false
|
||||
echoMode: password ? TextInput.Password : TextInput.Normal
|
||||
|
||||
Keys.onPressed: {
|
||||
if (event.key == Qt.Key_Return) {
|
||||
if (event.key == Qt.Key_Return || event.key == Qt.Key_Space) {
|
||||
mirrorText.text = "";
|
||||
event.accepted = true;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@ import QtQuick.Controls.Styles 1.4
|
|||
import "../styles-uit"
|
||||
import "../controls-uit" as HifiControls
|
||||
|
||||
import TabletScriptingInterface 1.0
|
||||
|
||||
Original.RadioButton {
|
||||
id: radioButton
|
||||
HifiConstants { id: hifi }
|
||||
|
@ -27,6 +29,15 @@ Original.RadioButton {
|
|||
readonly property int checkSize: 10
|
||||
readonly property int checkRadius: 2
|
||||
|
||||
onClicked: {
|
||||
tabletInterface.playSound(TabletEnums.ButtonClick);
|
||||
}
|
||||
|
||||
// TODO: doesnt works for QQC1. check with QQC2
|
||||
// onHovered: {
|
||||
// tabletInterface.playSound(TabletEnums.ButtonHover);
|
||||
// }
|
||||
|
||||
style: RadioButtonStyle {
|
||||
indicator: Rectangle {
|
||||
id: box
|
||||
|
|
|
@ -39,6 +39,20 @@ TextField {
|
|||
|
||||
y: textFieldLabel.visible ? textFieldLabel.height + textFieldLabel.anchors.bottomMargin : 0
|
||||
|
||||
// workaround for https://bugreports.qt.io/browse/QTBUG-49297
|
||||
Keys.onPressed: {
|
||||
switch (event.key) {
|
||||
case Qt.Key_Return:
|
||||
case Qt.Key_Enter:
|
||||
event.accepted = true;
|
||||
|
||||
// emit accepted signal manually
|
||||
if (acceptableInput) {
|
||||
accepted();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
style: TextFieldStyle {
|
||||
textColor: {
|
||||
if (isLightColorScheme) {
|
||||
|
|
|
@ -16,6 +16,7 @@ Item {
|
|||
property bool keyboardEnabled: false
|
||||
property bool keyboardRaised: false
|
||||
property bool punctuationMode: false
|
||||
property bool passwordField: false
|
||||
property bool isDesktop: false
|
||||
property alias webView: web.webViewCore
|
||||
property alias profile: web.webViewCoreProfile
|
||||
|
@ -41,7 +42,7 @@ Item {
|
|||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
spacing: 120
|
||||
|
||||
|
||||
TabletWebButton {
|
||||
id: back
|
||||
enabledColor: hifi.colors.darkGray
|
||||
|
@ -165,6 +166,11 @@ Item {
|
|||
id: keyboard
|
||||
raised: parent.keyboardEnabled && parent.keyboardRaised
|
||||
numeric: parent.punctuationMode
|
||||
password: parent.passwordField
|
||||
|
||||
onPasswordChanged: {
|
||||
keyboard.mirroredText = "";
|
||||
}
|
||||
|
||||
anchors {
|
||||
left: parent.left
|
||||
|
@ -172,7 +178,7 @@ Item {
|
|||
bottom: parent.bottom
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Component.onCompleted: {
|
||||
root.isDesktop = (typeof desktop !== "undefined");
|
||||
keyboardEnabled = HMD.active;
|
||||
|
|
|
@ -13,6 +13,7 @@ Item {
|
|||
property bool keyboardEnabled: true // FIXME - Keyboard HMD only: Default to false
|
||||
property bool keyboardRaised: false
|
||||
property bool punctuationMode: false
|
||||
property bool passwordField: false
|
||||
property alias flickable: webroot.interactive
|
||||
|
||||
// FIXME - Keyboard HMD only: Make Interface either set keyboardRaised property directly in OffscreenQmlSurface
|
||||
|
@ -50,6 +51,7 @@ Item {
|
|||
id: keyboard
|
||||
raised: parent.keyboardEnabled && parent.keyboardRaised
|
||||
numeric: parent.punctuationMode
|
||||
password: parent.passwordField
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
|
|
|
@ -88,7 +88,7 @@ FocusScope {
|
|||
return;
|
||||
}
|
||||
var oldRecommendedRect = recommendedRect;
|
||||
var newRecommendedRectJS = (typeof Controller === "undefined") ? Qt.rect(0,0,0,0) : Controller.getRecommendedOverlayRect();
|
||||
var newRecommendedRectJS = (typeof Controller === "undefined") ? Qt.rect(0,0,0,0) : Controller.getRecommendedHUDRect();
|
||||
var newRecommendedRect = Qt.rect(newRecommendedRectJS.x, newRecommendedRectJS.y,
|
||||
newRecommendedRectJS.width,
|
||||
newRecommendedRectJS.height);
|
||||
|
@ -271,7 +271,7 @@ FocusScope {
|
|||
|
||||
var oldRecommendedRect = recommendedRect;
|
||||
var oldRecommendedDimmensions = { x: oldRecommendedRect.width, y: oldRecommendedRect.height };
|
||||
var newRecommendedRect = Controller.getRecommendedOverlayRect();
|
||||
var newRecommendedRect = Controller.getRecommendedHUDRect();
|
||||
var newRecommendedDimmensions = { x: newRecommendedRect.width, y: newRecommendedRect.height };
|
||||
var windows = d.getTopLevelWindows();
|
||||
for (var i = 0; i < windows.length; ++i) {
|
||||
|
@ -301,15 +301,19 @@ FocusScope {
|
|||
function isPointOnWindow(point) {
|
||||
for (var i = 0; i < desktop.visibleChildren.length; i++) {
|
||||
var child = desktop.visibleChildren[i];
|
||||
if (child.visible) {
|
||||
if (child.hasOwnProperty("modality")) {
|
||||
var mappedPoint = child.mapFromGlobal(point.x, point.y);
|
||||
if (child.hasOwnProperty("modality")) {
|
||||
var mappedPoint = mapToItem(child, point.x, point.y);
|
||||
if (child.hasOwnProperty("frame")) {
|
||||
var outLine = child.frame.children[2];
|
||||
var framePoint = outLine.mapFromGlobal(point.x, point.y);
|
||||
if (child.contains(mappedPoint) || outLine.contains(framePoint)) {
|
||||
if (outLine.contains(framePoint)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (child.contains(mappedPoint)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -410,7 +414,7 @@ FocusScope {
|
|||
return;
|
||||
}
|
||||
|
||||
var newRecommendedRectJS = (typeof Controller === "undefined") ? Qt.rect(0,0,0,0) : Controller.getRecommendedOverlayRect();
|
||||
var newRecommendedRectJS = (typeof Controller === "undefined") ? Qt.rect(0,0,0,0) : Controller.getRecommendedHUDRect();
|
||||
var newRecommendedRect = Qt.rect(newRecommendedRectJS.x, newRecommendedRectJS.y,
|
||||
newRecommendedRectJS.width,
|
||||
newRecommendedRectJS.height);
|
||||
|
@ -442,7 +446,7 @@ FocusScope {
|
|||
|
||||
var oldRecommendedRect = recommendedRect;
|
||||
var oldRecommendedDimmensions = { x: oldRecommendedRect.width, y: oldRecommendedRect.height };
|
||||
var newRecommendedRect = Controller.getRecommendedOverlayRect();
|
||||
var newRecommendedRect = Controller.getRecommendedHUDRect();
|
||||
var newRecommendedDimmensions = { x: newRecommendedRect.width, y: newRecommendedRect.height };
|
||||
repositionWindow(targetWindow, false, oldRecommendedRect, oldRecommendedDimmensions, newRecommendedRect, newRecommendedDimmensions);
|
||||
}
|
||||
|
@ -459,7 +463,7 @@ FocusScope {
|
|||
return;
|
||||
}
|
||||
|
||||
var recommended = Controller.getRecommendedOverlayRect();
|
||||
var recommended = Controller.getRecommendedHUDRect();
|
||||
var maxX = recommended.x + recommended.width;
|
||||
var maxY = recommended.y + recommended.height;
|
||||
var newPosition = Qt.vector2d(targetWindow.x, targetWindow.y);
|
||||
|
|
|
@ -37,6 +37,8 @@ TabletModalWindow {
|
|||
property bool keyboardEnabled: false
|
||||
property bool keyboardRaised: false
|
||||
property bool punctuationMode: false
|
||||
property bool isPassword: false
|
||||
property alias text: loginKeyboard.mirroredText
|
||||
|
||||
readonly property bool isTablet: true
|
||||
|
||||
|
@ -130,6 +132,7 @@ TabletModalWindow {
|
|||
id: loginKeyboard
|
||||
raised: root.keyboardEnabled && root.keyboardRaised
|
||||
numeric: root.punctuationMode
|
||||
password: root.isPassword
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
|
|
|
@ -33,7 +33,7 @@ Window {
|
|||
|
||||
BaseWebView {
|
||||
id: webview
|
||||
url: "https://metaverse.highfidelity.com/marketplace?category=avatars"
|
||||
url: Account.metaverseServerURL + "/marketplace?category=avatars"
|
||||
focus: true
|
||||
|
||||
anchors {
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import TabletScriptingInterface 1.0
|
||||
|
||||
import "../../controls-uit"
|
||||
|
||||
|
@ -22,7 +23,16 @@ Preference {
|
|||
|
||||
Button {
|
||||
id: button
|
||||
onClicked: preference.trigger()
|
||||
onHoveredChanged: {
|
||||
if (hovered) {
|
||||
tabletInterface.playSound(TabletEnums.ButtonHover);
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
preference.trigger();
|
||||
tabletInterface.playSound(TabletEnums.ButtonClick);
|
||||
}
|
||||
width: 180
|
||||
anchors.bottom: parent.bottom
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import TabletScriptingInterface 1.0
|
||||
|
||||
import "../../controls-uit"
|
||||
|
||||
|
@ -38,6 +39,16 @@ Preference {
|
|||
|
||||
CheckBox {
|
||||
id: checkBox
|
||||
onHoveredChanged: {
|
||||
if (hovered) {
|
||||
tabletInterface.playSound(TabletEnums.ButtonHover);
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
tabletInterface.playSound(TabletEnums.ButtonClick);
|
||||
}
|
||||
|
||||
anchors {
|
||||
top: spacer.bottom
|
||||
left: parent.left
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
import Hifi 1.0
|
||||
import QtQuick 2.5
|
||||
import QtGraphicalEffects 1.0
|
||||
import TabletScriptingInterface 1.0
|
||||
|
||||
import "toolbars"
|
||||
import "../styles-uit"
|
||||
|
||||
|
@ -243,9 +245,15 @@ Item {
|
|||
MouseArea {
|
||||
anchors.fill: parent;
|
||||
acceptedButtons: Qt.LeftButton;
|
||||
onClicked: goFunction("hifi://" + hifiUrl);
|
||||
onClicked: {
|
||||
tabletInterface.playSound(TabletEnums.ButtonClick);
|
||||
goFunction("hifi://" + hifiUrl);
|
||||
}
|
||||
hoverEnabled: true;
|
||||
onEntered: hoverThunk();
|
||||
onEntered: {
|
||||
tabletInterface.playSound(TabletEnums.ButtonHover);
|
||||
hoverThunk();
|
||||
}
|
||||
onExited: unhoverThunk();
|
||||
}
|
||||
StateImage {
|
||||
|
@ -261,6 +269,7 @@ Item {
|
|||
}
|
||||
}
|
||||
function go() {
|
||||
tabletInterface.playSound(TabletEnums.ButtonClick);
|
||||
goFunction(drillDownToPlace ? ("/places/" + placeName) : ("/user_stories/" + storyId));
|
||||
}
|
||||
MouseArea {
|
||||
|
|
|
@ -17,7 +17,7 @@ import "../styles-uit"
|
|||
import "../controls-uit" as HifiControls
|
||||
import "toolbars"
|
||||
|
||||
// references Users, UserActivityLogger, MyAvatar, Vec3, Quat, AddressManager from root context
|
||||
// references Users, UserActivityLogger, MyAvatar, Vec3, Quat, AddressManager, Account from root context
|
||||
|
||||
Item {
|
||||
id: thisNameCard
|
||||
|
@ -30,7 +30,6 @@ Item {
|
|||
|
||||
// Properties
|
||||
property string profileUrl: "";
|
||||
property string defaultBaseUrl: AddressManager.metaverseServerUrl;
|
||||
property string connectionStatus : ""
|
||||
property string uuid: ""
|
||||
property string displayName: ""
|
||||
|
@ -59,7 +58,7 @@ Item {
|
|||
clip: true
|
||||
Image {
|
||||
id: userImage
|
||||
source: profileUrl !== "" ? ((0 === profileUrl.indexOf("http")) ? profileUrl : (defaultBaseUrl + profileUrl)) : "";
|
||||
source: profileUrl !== "" ? ((0 === profileUrl.indexOf("http")) ? profileUrl : (Account.metaverseServerURL + profileUrl)) : "";
|
||||
mipmap: true;
|
||||
// Anchors
|
||||
anchors.fill: parent
|
||||
|
@ -95,7 +94,7 @@ Item {
|
|||
enabled: (selected && activeTab == "nearbyTab") || isMyCard;
|
||||
hoverEnabled: enabled
|
||||
onClicked: {
|
||||
userInfoViewer.url = defaultBaseUrl + "/users/" + userName;
|
||||
userInfoViewer.url = Account.metaverseServerURL + "/users/" + userName;
|
||||
userInfoViewer.visible = true;
|
||||
}
|
||||
onEntered: infoHoverImage.visible = true;
|
||||
|
@ -366,7 +365,7 @@ Item {
|
|||
enabled: selected
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
userInfoViewer.url = defaultBaseUrl + "/users/" + userName;
|
||||
userInfoViewer.url = Account.metaverseServerURL + "/users/" + userName;
|
||||
userInfoViewer.visible = true;
|
||||
}
|
||||
onEntered: {
|
||||
|
|
|
@ -23,9 +23,6 @@ import "../controls" as HifiControls
|
|||
|
||||
Rectangle {
|
||||
id: pal;
|
||||
// Size
|
||||
width: parent.width;
|
||||
height: parent.height;
|
||||
// Style
|
||||
color: "#E3E3E3";
|
||||
// Properties
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// skyboxchanger.qml
|
||||
//
|
||||
// SkyboxChanger.qml
|
||||
// qml/hifi
|
||||
//
|
||||
// Created by Cain Kilgore on 9th August 2017
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
|
@ -9,33 +9,73 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick.Layouts 1.3
|
||||
import QtQuick 2.5
|
||||
import "../styles-uit"
|
||||
import "../controls-uit" as HifiControls
|
||||
import QtQuick.Controls 2.2
|
||||
|
||||
Rectangle {
|
||||
Item {
|
||||
id: root;
|
||||
|
||||
color: hifi.colors.baseGray;
|
||||
|
||||
HifiConstants { id: hifi; }
|
||||
|
||||
property var defaultThumbnails: [];
|
||||
property var defaultFulls: [];
|
||||
|
||||
ListModel {
|
||||
id: skyboxModel;
|
||||
}
|
||||
|
||||
function getSkyboxes() {
|
||||
var xmlhttp = new XMLHttpRequest();
|
||||
var url = "http://mpassets.highfidelity.com/5fbdbeef-1cf8-4954-811d-3d4acbba4dc9-v1/skyboxes.json";
|
||||
xmlhttp.onreadystatechange = function() {
|
||||
if (xmlhttp.readyState === XMLHttpRequest.DONE && xmlhttp.status === 200) {
|
||||
sortSkyboxes(xmlhttp.responseText);
|
||||
}
|
||||
}
|
||||
xmlhttp.open("GET", url, true);
|
||||
xmlhttp.send();
|
||||
}
|
||||
|
||||
function sortSkyboxes(response) {
|
||||
var arr = JSON.parse(response);
|
||||
var arrLength = arr.length;
|
||||
for (var i = 0; i < arrLength; i++) {
|
||||
defaultThumbnails.push(arr[i].thumb);
|
||||
defaultFulls.push(arr[i].full);
|
||||
skyboxModel.append({});
|
||||
}
|
||||
setSkyboxes();
|
||||
}
|
||||
|
||||
function setSkyboxes() {
|
||||
for (var i = 0; i < skyboxModel.count; i++) {
|
||||
skyboxModel.setProperty(i, "thumbnailPath", defaultThumbnails[i]);
|
||||
skyboxModel.setProperty(i, "fullSkyboxPath", defaultFulls[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
getSkyboxes();
|
||||
}
|
||||
|
||||
Item {
|
||||
id: titleBarContainer;
|
||||
// Size
|
||||
width: parent.width;
|
||||
height: 50;
|
||||
// Anchors
|
||||
height: childrenRect.height;
|
||||
anchors.left: parent.left;
|
||||
anchors.top: parent.top;
|
||||
|
||||
RalewaySemiBold {
|
||||
anchors.right: parent.right;
|
||||
anchors.topMargin: 20;
|
||||
RalewayBold {
|
||||
id: titleBarText;
|
||||
text: "Skybox Changer";
|
||||
// Text size
|
||||
size: hifi.fontSizes.overlayTitle;
|
||||
// Anchors
|
||||
anchors.fill: parent;
|
||||
anchors.leftMargin: 16;
|
||||
// Style
|
||||
anchors.top: parent.top;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 40
|
||||
height: paintedHeight;
|
||||
color: hifi.colors.lightGrayText;
|
||||
// Alignment
|
||||
horizontalAlignment: Text.AlignHCenter;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
}
|
||||
|
@ -43,131 +83,61 @@ Rectangle {
|
|||
id: titleBarDesc;
|
||||
text: "Click an image to choose a new Skybox.";
|
||||
wrapMode: Text.Wrap
|
||||
// Text size
|
||||
size: 14;
|
||||
// Anchors
|
||||
anchors.fill: parent;
|
||||
anchors.top: titleBarText.bottom
|
||||
anchors.leftMargin: 16;
|
||||
anchors.rightMargin: 16;
|
||||
// Style
|
||||
anchors.top: titleBarText.bottom;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 40
|
||||
height: paintedHeight;
|
||||
color: hifi.colors.lightGrayText;
|
||||
// Alignment
|
||||
horizontalAlignment: Text.AlignHCenter;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This RowLayout could be a GridLayout instead for further expandability.
|
||||
// As this SkyboxChanger task only required 6 images, implementing GridLayout wasn't necessary.
|
||||
// In the future if this is to be expanded to add more Skyboxes, it might be worth changing this.
|
||||
RowLayout {
|
||||
id: row1
|
||||
GridView {
|
||||
id: gridView
|
||||
interactive: true
|
||||
clip: true
|
||||
anchors.top: titleBarContainer.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 30
|
||||
Layout.fillWidth: true
|
||||
anchors.topMargin: 30
|
||||
spacing: 10
|
||||
Image {
|
||||
width: 200; height: 200
|
||||
fillMode: Image.Stretch
|
||||
source: "http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/thumbnails/thumb_1.jpg"
|
||||
clip: true
|
||||
id: preview1
|
||||
MouseArea {
|
||||
anchors.topMargin: 20
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: 400
|
||||
anchors.bottom: parent.bottom
|
||||
currentIndex: -1
|
||||
cellWidth: 200
|
||||
cellHeight: 200
|
||||
model: skyboxModel
|
||||
delegate: Item {
|
||||
width: gridView.cellWidth
|
||||
height: gridView.cellHeight
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
sendToScript({method: 'changeSkybox', url: 'http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/skyboxes/1.jpg'});
|
||||
Image {
|
||||
source: thumbnailPath
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
fillMode: Image.Stretch
|
||||
sourceSize.width: parent.width
|
||||
sourceSize.height: parent.height
|
||||
mipmap: true
|
||||
}
|
||||
}
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Image {
|
||||
width: 200; height: 200
|
||||
fillMode: Image.Stretch
|
||||
source: "http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/thumbnails/thumb_2.jpg"
|
||||
clip: true
|
||||
id: preview2
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
sendToScript({method: 'changeSkybox', url: 'http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/skyboxes/2.png'});
|
||||
sendToScript({method: 'changeSkybox', url: fullSkyboxPath});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
id: row2
|
||||
anchors.top: row1.bottom
|
||||
anchors.topMargin: 10
|
||||
anchors.left: parent.left
|
||||
Layout.fillWidth: true
|
||||
anchors.leftMargin: 30
|
||||
spacing: 10
|
||||
Image {
|
||||
width: 200; height: 200
|
||||
fillMode: Image.Stretch
|
||||
source: "http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/thumbnails/thumb_3.jpg"
|
||||
clip: true
|
||||
id: preview3
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
sendToScript({method: 'changeSkybox', url: 'http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/skyboxes/3.jpg'});
|
||||
}
|
||||
}
|
||||
}
|
||||
Image {
|
||||
width: 200; height: 200
|
||||
fillMode: Image.Stretch
|
||||
source: "http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/thumbnails/thumb_4.jpg"
|
||||
clip: true
|
||||
id: preview4
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
sendToScript({method: 'changeSkybox', url: 'http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/skyboxes/4.jpg'});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
id: row3
|
||||
anchors.top: row2.bottom
|
||||
anchors.topMargin: 10
|
||||
anchors.left: parent.left
|
||||
Layout.fillWidth: true
|
||||
anchors.leftMargin: 30
|
||||
spacing: 10
|
||||
Image {
|
||||
width: 200; height: 200
|
||||
fillMode: Image.Stretch
|
||||
source: "http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/thumbnails/thumb_5.jpg"
|
||||
clip: true
|
||||
id: preview5
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
sendToScript({method: 'changeSkybox', url: 'http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/skyboxes/5.png'});
|
||||
}
|
||||
}
|
||||
}
|
||||
Image {
|
||||
width: 200; height: 200
|
||||
fillMode: Image.Stretch
|
||||
source: "http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/thumbnails/thumb_6.jpg"
|
||||
clip: true
|
||||
id: preview6
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
sendToScript({method: 'changeSkybox', url: 'http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/skyboxes/6.jpg'});
|
||||
}
|
||||
}
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
parent: gridView.parent
|
||||
anchors.top: gridView.top
|
||||
anchors.left: gridView.right
|
||||
anchors.bottom: gridView.bottom
|
||||
anchors.leftMargin: 10
|
||||
width: 19
|
||||
}
|
||||
}
|
||||
|
||||
signal sendToScript(var message);
|
||||
|
||||
}
|
||||
}
|
|
@ -14,6 +14,8 @@ import QtQuick.Controls 1.4
|
|||
import QtQuick.Layouts 1.3
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
import TabletScriptingInterface 1.0
|
||||
|
||||
Rectangle {
|
||||
readonly property var level: Audio.inputLevel;
|
||||
|
||||
|
@ -57,8 +59,16 @@ Rectangle {
|
|||
|
||||
hoverEnabled: true;
|
||||
scrollGestureEnabled: false;
|
||||
onClicked: { Audio.muted = !Audio.muted; }
|
||||
onClicked: {
|
||||
Audio.muted = !Audio.muted;
|
||||
tabletInterface.playSound(TabletEnums.ButtonClick);
|
||||
}
|
||||
drag.target: dragTarget;
|
||||
onContainsMouseChanged: {
|
||||
if (containsMouse) {
|
||||
tabletInterface.playSound(TabletEnums.ButtonHover);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QtObject {
|
||||
|
|
|
@ -22,8 +22,7 @@ RowLayout {
|
|||
property var sample: null;
|
||||
property bool isPlaying: false;
|
||||
function createSampleSound() {
|
||||
var SOUND = Qt.resolvedUrl("../../../sounds/sample.wav");
|
||||
sound = SoundCache.getSound(SOUND);
|
||||
sound = ApplicationInterface.getSampleSound();
|
||||
sample = null;
|
||||
}
|
||||
function playSound() {
|
||||
|
|
|
@ -39,7 +39,8 @@ Rectangle {
|
|||
property bool itemIsJson: true;
|
||||
property bool shouldBuyWithControlledFailure: false;
|
||||
property bool debugCheckoutSuccess: false;
|
||||
property bool canRezCertifiedItems: Entities.canRezCertified || Entities.canRezTmpCertified;
|
||||
property bool canRezCertifiedItems: Entities.canRezCertified() || Entities.canRezTmpCertified();
|
||||
property bool isWearable;
|
||||
// Style
|
||||
color: hifi.colors.white;
|
||||
Hifi.QmlCommerce {
|
||||
|
@ -79,6 +80,8 @@ Rectangle {
|
|||
failureErrorText.text = result.message;
|
||||
root.activeView = "checkoutFailure";
|
||||
} else {
|
||||
root.itemHref = result.data.download_url;
|
||||
root.isWearable = result.data.categories.indexOf("Wearables") > -1;
|
||||
root.activeView = "checkoutSuccess";
|
||||
}
|
||||
}
|
||||
|
@ -114,7 +117,7 @@ Rectangle {
|
|||
}
|
||||
|
||||
onItemHrefChanged: {
|
||||
itemIsJson = root.itemHref.indexOf('.json') !== -1;
|
||||
itemIsJson = root.itemHref.endsWith('.json');
|
||||
}
|
||||
|
||||
onItemPriceChanged: {
|
||||
|
@ -125,7 +128,7 @@ Rectangle {
|
|||
id: notSetUpTimer;
|
||||
interval: 200;
|
||||
onTriggered: {
|
||||
sendToScript({method: 'checkout_walletNotSetUp'});
|
||||
sendToScript({method: 'checkout_walletNotSetUp', itemId: itemId});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -238,6 +241,25 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HifiCommerceCommon.FirstUseTutorial {
|
||||
id: firstUseTutorial;
|
||||
z: 999;
|
||||
visible: root.activeView === "firstUseTutorial";
|
||||
anchors.fill: parent;
|
||||
|
||||
Connections {
|
||||
onSendSignalToParent: {
|
||||
switch (message.method) {
|
||||
case 'tutorial_skipClicked':
|
||||
case 'tutorial_finished':
|
||||
Settings.setValue("isFirstUseOfPurchases", false);
|
||||
root.activeView = "checkoutSuccess";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -563,7 +585,7 @@ Rectangle {
|
|||
// "Rez" button
|
||||
HifiControlsUit.Button {
|
||||
id: rezNowButton;
|
||||
enabled: root.canRezCertifiedItems;
|
||||
enabled: root.canRezCertifiedItems || root.isWearable;
|
||||
buttonGlyph: hifi.glyphs.lightning;
|
||||
color: hifi.buttons.red;
|
||||
colorScheme: hifi.colorSchemes.light;
|
||||
|
@ -572,10 +594,10 @@ Rectangle {
|
|||
height: 50;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
text: "Rez It"
|
||||
text: root.isWearable ? "Wear It" : "Rez It"
|
||||
onClicked: {
|
||||
if (urlHandler.canHandleUrl(itemHref)) {
|
||||
urlHandler.handleUrl(itemHref);
|
||||
if (urlHandler.canHandleUrl(root.itemHref)) {
|
||||
urlHandler.handleUrl(root.itemHref);
|
||||
}
|
||||
rezzedNotifContainer.visible = true;
|
||||
rezzedNotifContainerTimer.start();
|
||||
|
@ -583,7 +605,7 @@ Rectangle {
|
|||
}
|
||||
RalewaySemiBold {
|
||||
id: noPermissionText;
|
||||
visible: !root.canRezCertifiedItems;
|
||||
visible: !root.canRezCertifiedItems && !root.isWearable;
|
||||
text: '<font color="' + hifi.colors.redAccent + '"><a href="#">You do not have Certified Rez permissions in this domain.</a></font>'
|
||||
// Text size
|
||||
size: 16;
|
||||
|
@ -610,6 +632,28 @@ Rectangle {
|
|||
lightboxPopup.visible = true;
|
||||
}
|
||||
}
|
||||
RalewaySemiBold {
|
||||
id: explainRezText;
|
||||
visible: !root.isWearable;
|
||||
text: '<font color="' + hifi.colors.redAccent + '"><a href="#">What does "Rez" mean?</a></font>'
|
||||
// Text size
|
||||
size: 16;
|
||||
// Anchors
|
||||
anchors.top: noPermissionText.visible ? noPermissionText.bottom : rezNowButton.bottom;
|
||||
anchors.topMargin: 6;
|
||||
height: paintedHeight;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
// Style
|
||||
color: hifi.colors.redAccent;
|
||||
wrapMode: Text.WordWrap;
|
||||
// Alignment
|
||||
horizontalAlignment: Text.AlignHCenter;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
onLinkActivated: {
|
||||
root.activeView = "firstUseTutorial";
|
||||
}
|
||||
}
|
||||
|
||||
RalewaySemiBold {
|
||||
id: myPurchasesLink;
|
||||
|
@ -617,7 +661,7 @@ Rectangle {
|
|||
// Text size
|
||||
size: 20;
|
||||
// Anchors
|
||||
anchors.top: noPermissionText.visible ? noPermissionText.bottom : rezNowButton.bottom;
|
||||
anchors.top: explainRezText.visible ? explainRezText.bottom : (noPermissionText.visible ? noPermissionText.bottom : rezNowButton.bottom);
|
||||
anchors.topMargin: 40;
|
||||
height: paintedHeight;
|
||||
anchors.left: parent.left;
|
||||
|
|
|
@ -25,7 +25,7 @@ Item {
|
|||
HifiConstants { id: hifi; }
|
||||
|
||||
id: root;
|
||||
property string referrerURL: "https://metaverse.highfidelity.com/marketplace?";
|
||||
property string referrerURL: (Account.metaverseServerURL + "/marketplace?");
|
||||
readonly property int additionalDropdownHeight: usernameDropdown.height - myUsernameButton.anchors.bottomMargin;
|
||||
property alias usernameDropdownVisible: usernameDropdown.visible;
|
||||
|
||||
|
|
|
@ -25,7 +25,13 @@ Rectangle {
|
|||
HifiConstants { id: hifi; }
|
||||
|
||||
id: root;
|
||||
property int activeView: 1;
|
||||
property int activeView: 1;
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
root.activeView = 1;
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
anchors.fill: parent;
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 72 KiB |
Before Width: | Height: | Size: 81 KiB After Width: | Height: | Size: 81 KiB |
|
@ -25,16 +25,107 @@ Rectangle {
|
|||
HifiConstants { id: hifi; }
|
||||
|
||||
id: root;
|
||||
property string marketplaceId: "";
|
||||
property string marketplaceUrl;
|
||||
property string certificateId;
|
||||
property string itemName: "--";
|
||||
property string itemOwner: "--";
|
||||
property string itemEdition: "--";
|
||||
property string dateOfPurchase: "";
|
||||
property string dateOfPurchase: "--";
|
||||
property bool isLightbox: false;
|
||||
property bool isMyCert: false;
|
||||
property bool isCertificateInvalid: false;
|
||||
// Style
|
||||
color: hifi.colors.faintGray;
|
||||
Hifi.QmlCommerce {
|
||||
id: commerce;
|
||||
|
||||
onCertificateInfoResult: {
|
||||
if (result.status !== 'success') {
|
||||
console.log("Failed to get certificate info", result.message);
|
||||
} else {
|
||||
root.marketplaceUrl = result.data.marketplace_item_url;
|
||||
root.isMyCert = result.isMyCert ? result.isMyCert : false;
|
||||
root.itemOwner = root.isCertificateInvalid ? "--" : (root.isMyCert ? Account.username :
|
||||
"\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022");
|
||||
root.itemEdition = root.isCertificateInvalid ? "Uncertified Copy" :
|
||||
(result.data.edition_number + "/" + (result.data.limited_run === -1 ? "\u221e" : result.data.limited_run));
|
||||
root.dateOfPurchase = root.isCertificateInvalid ? "" : getFormattedDate(result.data.transfer_created_at * 1000);
|
||||
root.itemName = result.data.marketplace_item_name;
|
||||
|
||||
if (result.data.invalid_reason || result.data.transfer_status[0] === "failed") {
|
||||
titleBarText.text = "Invalid Certificate";
|
||||
titleBarText.color = hifi.colors.redHighlight;
|
||||
popText.text = "";
|
||||
if (result.data.invalid_reason) {
|
||||
errorText.text = result.data.invalid_reason;
|
||||
}
|
||||
} else if (result.data.transfer_status[0] === "pending") {
|
||||
titleBarText.text = "Certificate Pending";
|
||||
errorText.text = "The status of this item is still pending confirmation. If the purchase is not confirmed, " +
|
||||
"this entity will be cleaned up by the domain.";
|
||||
errorText.color = hifi.colors.baseGray;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onUpdateCertificateStatus: {
|
||||
if (certStatus === 1) { // CERTIFICATE_STATUS_VERIFICATION_SUCCESS
|
||||
// NOP
|
||||
} else if (certStatus === 2) { // CERTIFICATE_STATUS_VERIFICATION_TIMEOUT
|
||||
root.isCertificateInvalid = true;
|
||||
errorText.text = "Verification of this certificate timed out.";
|
||||
errorText.color = hifi.colors.redHighlight;
|
||||
} else if (certStatus === 3) { // CERTIFICATE_STATUS_STATIC_VERIFICATION_FAILED
|
||||
root.isCertificateInvalid = true;
|
||||
titleBarText.text = "Invalid Certificate";
|
||||
titleBarText.color = hifi.colors.redHighlight;
|
||||
|
||||
popText.text = "";
|
||||
root.itemOwner = "";
|
||||
dateOfPurchaseHeader.text = "";
|
||||
root.dateOfPurchase = "";
|
||||
root.itemEdition = "Uncertified Copy";
|
||||
|
||||
errorText.text = "The information associated with this item has been modified and it no longer matches the original certified item.";
|
||||
errorText.color = hifi.colors.baseGray;
|
||||
} else if (certStatus === 4) { // CERTIFICATE_STATUS_OWNER_VERIFICATION_FAILED
|
||||
root.isCertificateInvalid = true;
|
||||
titleBarText.text = "Invalid Certificate";
|
||||
titleBarText.color = hifi.colors.redHighlight;
|
||||
|
||||
popText.text = "";
|
||||
root.itemOwner = "";
|
||||
dateOfPurchaseHeader.text = "";
|
||||
root.dateOfPurchase = "";
|
||||
root.itemEdition = "Uncertified Copy";
|
||||
|
||||
errorText.text = "The avatar who rezzed this item doesn't own it.";
|
||||
errorText.color = hifi.colors.baseGray;
|
||||
} else {
|
||||
console.log("Unknown certificate status received from ledger signal!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onCertificateIdChanged: {
|
||||
if (certificateId !== "") {
|
||||
commerce.certificateInfo(certificateId);
|
||||
}
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (!visible) {
|
||||
titleBarText.text = "Certificate";
|
||||
popText.text = "PROOF OF PURCHASE";
|
||||
root.certificateId = "";
|
||||
root.itemName = "--";
|
||||
root.itemOwner = "--";
|
||||
root.itemEdition = "--";
|
||||
root.dateOfPurchase = "--";
|
||||
root.marketplaceUrl = "";
|
||||
root.isMyCert = false;
|
||||
errorText.text = "";
|
||||
}
|
||||
}
|
||||
|
||||
// This object is always used in a popup.
|
||||
|
@ -115,7 +206,7 @@ Rectangle {
|
|||
size: 28;
|
||||
// Anchors
|
||||
anchors.top: itemNameHeader.bottom;
|
||||
anchors.topMargin: 4;
|
||||
anchors.topMargin: 8;
|
||||
anchors.left: itemNameHeader.left;
|
||||
anchors.right: itemNameHeader.right;
|
||||
height: paintedHeight;
|
||||
|
@ -126,7 +217,7 @@ Rectangle {
|
|||
anchors.fill: parent;
|
||||
hoverEnabled: enabled;
|
||||
onClicked: {
|
||||
sendToScript({method: 'inspectionCertificate_showInMarketplaceClicked', itemId: root.marketplaceId});
|
||||
sendToScript({method: 'inspectionCertificate_showInMarketplaceClicked', marketplaceUrl: root.marketplaceUrl});
|
||||
}
|
||||
onEntered: itemName.color = hifi.colors.blueHighlight;
|
||||
onExited: itemName.color = hifi.colors.blueAccent;
|
||||
|
@ -140,14 +231,14 @@ Rectangle {
|
|||
size: 16;
|
||||
// Anchors
|
||||
anchors.top: itemName.bottom;
|
||||
anchors.topMargin: 20;
|
||||
anchors.topMargin: 28;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 45;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 16;
|
||||
height: paintedHeight;
|
||||
// Style
|
||||
color: hifi.colors.baseGray;
|
||||
color: hifi.colors.lightGray;
|
||||
}
|
||||
RalewayRegular {
|
||||
id: ownedBy;
|
||||
|
@ -156,14 +247,30 @@ Rectangle {
|
|||
size: 22;
|
||||
// Anchors
|
||||
anchors.top: ownedByHeader.bottom;
|
||||
anchors.topMargin: 4;
|
||||
anchors.topMargin: 8;
|
||||
anchors.left: ownedByHeader.left;
|
||||
anchors.right: ownedByHeader.right;
|
||||
height: paintedHeight;
|
||||
// Style
|
||||
color: hifi.colors.darkGray;
|
||||
elide: Text.ElideRight;
|
||||
}
|
||||
AnonymousProRegular {
|
||||
id: isMyCertText;
|
||||
visible: root.isMyCert && !root.isCertificateInvalid;
|
||||
text: "(Private)";
|
||||
size: 18;
|
||||
// Anchors
|
||||
anchors.top: ownedBy.top;
|
||||
anchors.topMargin: 4;
|
||||
anchors.bottom: ownedBy.bottom;
|
||||
anchors.left: ownedBy.right;
|
||||
anchors.leftMargin: 6;
|
||||
anchors.right: ownedByHeader.right;
|
||||
// Style
|
||||
color: hifi.colors.lightGray;
|
||||
elide: Text.ElideRight;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
}
|
||||
|
||||
RalewayRegular {
|
||||
id: editionHeader;
|
||||
|
@ -172,23 +279,23 @@ Rectangle {
|
|||
size: 16;
|
||||
// Anchors
|
||||
anchors.top: ownedBy.bottom;
|
||||
anchors.topMargin: 20;
|
||||
anchors.topMargin: 28;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 45;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 16;
|
||||
height: paintedHeight;
|
||||
// Style
|
||||
color: hifi.colors.baseGray;
|
||||
color: hifi.colors.lightGray;
|
||||
}
|
||||
AnonymousProRegular {
|
||||
id: edition;
|
||||
text: root.itemEdition;
|
||||
// Text size
|
||||
size: 22;
|
||||
size: 18;
|
||||
// Anchors
|
||||
anchors.top: editionHeader.bottom;
|
||||
anchors.topMargin: 4;
|
||||
anchors.topMargin: 8;
|
||||
anchors.left: editionHeader.left;
|
||||
anchors.right: editionHeader.right;
|
||||
height: paintedHeight;
|
||||
|
@ -199,31 +306,29 @@ Rectangle {
|
|||
RalewayRegular {
|
||||
id: dateOfPurchaseHeader;
|
||||
text: "DATE OF PURCHASE";
|
||||
visible: root.dateOfPurchase !== "";
|
||||
// Text size
|
||||
size: 16;
|
||||
// Anchors
|
||||
anchors.top: ownedBy.bottom;
|
||||
anchors.topMargin: 20;
|
||||
anchors.top: edition.bottom;
|
||||
anchors.topMargin: 28;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 45;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 16;
|
||||
height: paintedHeight;
|
||||
// Style
|
||||
color: hifi.colors.baseGray;
|
||||
color: hifi.colors.lightGray;
|
||||
}
|
||||
AnonymousProRegular {
|
||||
id: dateOfPurchase;
|
||||
text: root.dateOfPurchase;
|
||||
visible: root.dateOfPurchase !== "";
|
||||
// Text size
|
||||
size: 22;
|
||||
size: 18;
|
||||
// Anchors
|
||||
anchors.top: editionHeader.bottom;
|
||||
anchors.topMargin: 4;
|
||||
anchors.left: editionHeader.left;
|
||||
anchors.right: editionHeader.right;
|
||||
anchors.top: dateOfPurchaseHeader.bottom;
|
||||
anchors.topMargin: 8;
|
||||
anchors.left: dateOfPurchaseHeader.left;
|
||||
anchors.right: dateOfPurchaseHeader.right;
|
||||
height: paintedHeight;
|
||||
// Style
|
||||
color: hifi.colors.darkGray;
|
||||
|
@ -231,15 +336,13 @@ Rectangle {
|
|||
|
||||
RalewayRegular {
|
||||
id: errorText;
|
||||
text: "Here we will display some text if there's an <b>error</b> with the certificate " +
|
||||
"(DMCA takedown, invalid cert, location of item updated)";
|
||||
// Text size
|
||||
size: 20;
|
||||
// Anchors
|
||||
anchors.top: root.dateOfPurchase !== "" ? dateOfPurchase.bottom : edition.bottom;
|
||||
anchors.topMargin: 40;
|
||||
anchors.left: root.dateOfPurchase !== "" ? dateOfPurchase.left : edition.left;
|
||||
anchors.right: root.dateOfPurchase !== "" ? dateOfPurchase.right : edition.right;
|
||||
anchors.top: dateOfPurchase.bottom;
|
||||
anchors.topMargin: 36;
|
||||
anchors.left: dateOfPurchase.left;
|
||||
anchors.right: dateOfPurchase.right;
|
||||
anchors.bottom: parent.bottom;
|
||||
// Style
|
||||
wrapMode: Text.WordWrap;
|
||||
|
@ -254,7 +357,7 @@ Rectangle {
|
|||
Item {
|
||||
id: buttonsContainer;
|
||||
anchors.bottom: parent.bottom;
|
||||
anchors.bottomMargin: 50;
|
||||
anchors.bottomMargin: 30;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
height: 50;
|
||||
|
@ -281,6 +384,7 @@ Rectangle {
|
|||
// "Show In Marketplace" button
|
||||
HifiControlsUit.Button {
|
||||
id: showInMarketplaceButton;
|
||||
enabled: root.marketplaceUrl;
|
||||
color: hifi.buttons.blue;
|
||||
colorScheme: hifi.colorSchemes.light;
|
||||
anchors.top: parent.top;
|
||||
|
@ -290,7 +394,7 @@ Rectangle {
|
|||
height: 50;
|
||||
text: "View In Market"
|
||||
onClicked: {
|
||||
sendToScript({method: 'inspectionCertificate_showInMarketplaceClicked', itemId: root.marketplaceId});
|
||||
sendToScript({method: 'inspectionCertificate_showInMarketplaceClicked', marketplaceUrl: root.marketplaceUrl});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -313,19 +417,42 @@ Rectangle {
|
|||
//
|
||||
function fromScript(message) {
|
||||
switch (message.method) {
|
||||
case 'inspectionCertificate_setMarketplaceId':
|
||||
root.marketplaceId = message.marketplaceId;
|
||||
break;
|
||||
case 'inspectionCertificate_setItemInfo':
|
||||
root.itemName = message.itemName;
|
||||
root.itemOwner = message.itemOwner;
|
||||
root.itemEdition = message.itemEdition;
|
||||
case 'inspectionCertificate_setCertificateId':
|
||||
root.certificateId = message.certificateId;
|
||||
break;
|
||||
default:
|
||||
console.log('Unrecognized message from marketplaces.js:', JSON.stringify(message));
|
||||
}
|
||||
}
|
||||
signal sendToScript(var message);
|
||||
|
||||
function getFormattedDate(timestamp) {
|
||||
function addLeadingZero(n) {
|
||||
return n < 10 ? '0' + n : '' + n;
|
||||
}
|
||||
|
||||
var a = new Date(timestamp);
|
||||
var year = a.getFullYear();
|
||||
var month = addLeadingZero(a.getMonth());
|
||||
var day = addLeadingZero(a.getDate());
|
||||
var hour = a.getHours();
|
||||
var drawnHour = hour;
|
||||
if (hour === 0) {
|
||||
drawnHour = 12;
|
||||
} else if (hour > 12) {
|
||||
drawnHour -= 12;
|
||||
}
|
||||
drawnHour = addLeadingZero(drawnHour);
|
||||
|
||||
var amOrPm = "AM";
|
||||
if (hour >= 12) {
|
||||
amOrPm = "PM";
|
||||
}
|
||||
|
||||
var min = addLeadingZero(a.getMinutes());
|
||||
var sec = addLeadingZero(a.getSeconds());
|
||||
return year + '-' + month + '-' + day + '<br>' + drawnHour + ':' + min + amOrPm;
|
||||
}
|
||||
//
|
||||
// FUNCTION DEFINITIONS END
|
||||
//
|
||||
|
|
|
@ -34,10 +34,12 @@ Item {
|
|||
property string itemId;
|
||||
property string itemPreviewImageUrl;
|
||||
property string itemHref;
|
||||
property string certificateId;
|
||||
property int displayedItemCount;
|
||||
property int itemEdition;
|
||||
property int numberSold;
|
||||
property int limitedRun;
|
||||
property bool isWearable;
|
||||
|
||||
property string originalStatusText;
|
||||
property string originalStatusColor;
|
||||
|
@ -168,7 +170,7 @@ Item {
|
|||
anchors.fill: parent;
|
||||
hoverEnabled: enabled;
|
||||
onClicked: {
|
||||
sendToPurchases({method: 'purchases_itemCertificateClicked', itemMarketplaceId: root.itemId});
|
||||
sendToPurchases({method: 'purchases_itemCertificateClicked', itemCertificateId: root.certificateId});
|
||||
}
|
||||
onEntered: {
|
||||
certificateIcon.color = hifi.colors.black;
|
||||
|
@ -225,7 +227,7 @@ Item {
|
|||
} else if (root.purchaseStatus === "invalidated") {
|
||||
"INVALIDATED"
|
||||
} else if (root.numberSold !== -1) {
|
||||
("Sales: " + root.numberSold + "/" + (root.limitedRun === -1 ? "INFTY" : root.limitedRun))
|
||||
("Sales: " + root.numberSold + "/" + (root.limitedRun === -1 ? "\u221e" : root.limitedRun))
|
||||
} else {
|
||||
""
|
||||
}
|
||||
|
@ -341,7 +343,7 @@ Item {
|
|||
anchors.bottom: parent.bottom;
|
||||
anchors.right: parent.right;
|
||||
width: height;
|
||||
enabled: root.canRezCertifiedItems && root.purchaseStatus !== "invalidated";
|
||||
enabled: (root.canRezCertifiedItems || root.isWearable) && root.purchaseStatus !== "invalidated";
|
||||
|
||||
onClicked: {
|
||||
if (urlHandler.canHandleUrl(root.itemHref)) {
|
||||
|
@ -414,7 +416,7 @@ Item {
|
|||
size: 16;
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: "Rez It"
|
||||
text: root.isWearable ? "Wear It" : "Rez It"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ Rectangle {
|
|||
property bool securityImageResultReceived: false;
|
||||
property bool purchasesReceived: false;
|
||||
property bool punctuationMode: false;
|
||||
property bool canRezCertifiedItems: Entities.canRezCertified || Entities.canRezTmpCertified;
|
||||
property bool canRezCertifiedItems: Entities.canRezCertified() || Entities.canRezTmpCertified();
|
||||
property bool pendingInventoryReply: true;
|
||||
property bool isShowingMyItems: false;
|
||||
property bool isDebuggingFirstUseTutorial: false;
|
||||
|
@ -78,6 +78,10 @@ Rectangle {
|
|||
onInventoryResult: {
|
||||
purchasesReceived = true;
|
||||
|
||||
if (root.pendingInventoryReply) {
|
||||
inventoryTimer.start();
|
||||
}
|
||||
|
||||
if (result.status !== 'success') {
|
||||
console.log("Failed to get purchases", result.message);
|
||||
} else {
|
||||
|
@ -98,10 +102,6 @@ Rectangle {
|
|||
previousPurchasesModel.append(inventoryResult);
|
||||
|
||||
buildFilteredPurchasesModel();
|
||||
|
||||
if (root.pendingInventoryReply) {
|
||||
inventoryTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
root.pendingInventoryReply = false;
|
||||
|
@ -112,7 +112,7 @@ Rectangle {
|
|||
id: notSetUpTimer;
|
||||
interval: 200;
|
||||
onTriggered: {
|
||||
sendToScript({method: 'checkout_walletNotSetUp'});
|
||||
sendToScript({method: 'purchases_walletNotSetUp'});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -241,7 +241,7 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
|
||||
FirstUseTutorial {
|
||||
HifiCommerceCommon.FirstUseTutorial {
|
||||
id: firstUseTutorial;
|
||||
z: 999;
|
||||
visible: root.activeView === "firstUseTutorial";
|
||||
|
@ -426,13 +426,15 @@ Rectangle {
|
|||
itemName: title;
|
||||
itemId: id;
|
||||
itemPreviewImageUrl: preview;
|
||||
itemHref: root_file_url;
|
||||
itemHref: download_url;
|
||||
certificateId: certificate_id;
|
||||
purchaseStatus: status;
|
||||
purchaseStatusChanged: statusChanged;
|
||||
itemEdition: model.edition_number;
|
||||
numberSold: model.number_sold;
|
||||
limitedRun: model.limited_run;
|
||||
displayedItemCount: model.displayedItemCount;
|
||||
isWearable: model.categories.indexOf("Wearables") > -1;
|
||||
anchors.topMargin: 12;
|
||||
anchors.bottomMargin: 12;
|
||||
|
||||
|
@ -581,9 +583,11 @@ Rectangle {
|
|||
|
||||
Timer {
|
||||
id: inventoryTimer;
|
||||
interval: 90000;
|
||||
interval: 4000; // Change this back to 90000 after demo
|
||||
//interval: 90000;
|
||||
onTriggered: {
|
||||
if (root.activeView === "purchasesMain" && !root.pendingInventoryReply) {
|
||||
console.log("Refreshing Purchases...");
|
||||
root.pendingInventoryReply = true;
|
||||
commerce.inventory();
|
||||
}
|
||||
|
@ -659,6 +663,8 @@ Rectangle {
|
|||
currentPurchasesModelStatus !== previousPurchasesModelStatus) {
|
||||
|
||||
purchasesModel.setProperty(i, "statusChanged", true);
|
||||
} else {
|
||||
purchasesModel.setProperty(i, "statusChanged", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -684,8 +690,7 @@ Rectangle {
|
|||
titleBarContainer.referrerURL = message.referrerURL;
|
||||
filterBar.text = message.filterText ? message.filterText : "";
|
||||
break;
|
||||
case 'inspectionCertificate_setMarketplaceId':
|
||||
case 'inspectionCertificate_setItemInfo':
|
||||
case 'inspectionCertificate_setCertificateId':
|
||||
inspectionCertificate.fromScript(message);
|
||||
break;
|
||||
case 'purchases_showMyItems':
|
||||
|
|
|
@ -25,17 +25,20 @@ Item {
|
|||
|
||||
id: root;
|
||||
property string keyFilePath;
|
||||
property bool showDebugButtons: true;
|
||||
|
||||
Hifi.QmlCommerce {
|
||||
id: commerce;
|
||||
|
||||
onKeyFilePathIfExistsResult: {
|
||||
keyFilePath = path;
|
||||
root.keyFilePath = path;
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
commerce.getKeyFilePathIfExists();
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
commerce.getKeyFilePathIfExists();
|
||||
}
|
||||
}
|
||||
|
||||
RalewaySemiBold {
|
||||
|
@ -54,6 +57,7 @@ Item {
|
|||
}
|
||||
HifiControlsUit.Button {
|
||||
id: clearCachedPassphraseButton;
|
||||
visible: root.showDebugButtons;
|
||||
color: hifi.buttons.black;
|
||||
colorScheme: hifi.colorSchemes.dark;
|
||||
anchors.top: parent.top;
|
||||
|
@ -69,6 +73,7 @@ Item {
|
|||
}
|
||||
HifiControlsUit.Button {
|
||||
id: resetButton;
|
||||
visible: root.showDebugButtons;
|
||||
color: hifi.buttons.red;
|
||||
colorScheme: hifi.colorSchemes.dark;
|
||||
anchors.top: clearCachedPassphraseButton.top;
|
||||
|
@ -88,22 +93,27 @@ Item {
|
|||
ListElement {
|
||||
isExpanded: false;
|
||||
question: "What are private keys?"
|
||||
answer: qsTr("A private key is a secret piece of text that is used to decrypt code.<br><br>In High Fidelity, <b>your private keys are used to decrypt the contents of your Wallet and Purchases.</b>");
|
||||
answer: qsTr("A private key is a secret piece of text that is used to prove ownership, unlock confidential information, and sign transactions.<br><br>In High Fidelity, <b>your private keys are used to securely access the contents of your Wallet and Purchases.</b>");
|
||||
}
|
||||
ListElement {
|
||||
isExpanded: false;
|
||||
question: "Where are my private keys stored?"
|
||||
answer: qsTr('Your private keys are <b>only stored on your hard drive</b> in High Fidelity Interface\'s AppData directory.<br><br><b><font color="#0093C5"><a href="#privateKeyPath">Tap here to open the file path of your hifikey in your file explorer.</a></font></b><br><br> You may backup this file by copying it to a USB flash drive, or to a service like Dropbox or Google Drive. Restore your backup by replacing the file in Interface\'s AppData directory with your backed-up copy.');
|
||||
answer: qsTr('By default, your private keys are <b>only stored on your hard drive</b> in High Fidelity Interface\'s AppData directory.<br><br><b><font color="#0093C5"><a href="#privateKeyPath">Tap here to open the folder where your HifiKeys are stored on your main display.</a></font></b>');
|
||||
}
|
||||
ListElement {
|
||||
isExpanded: false;
|
||||
question: "How can I backup my private keys?"
|
||||
answer: qsTr('You may backup the file containing your private keys by copying it to a USB flash drive, or to a service like Dropbox or Google Drive.<br><br>Restore your backup by replacing the file in Interface\'s AppData directory with your backed-up copy.<br><br><b><font color="#0093C5"><a href="#privateKeyPath">Tap here to open the folder where your HifiKeys are stored on your main display.</a></font></b>');
|
||||
}
|
||||
ListElement {
|
||||
isExpanded: false;
|
||||
question: "What happens if I lose my passphrase?"
|
||||
answer: qsTr("If you lose your passphrase, you will no longer have access to the contents of your Wallet or My Purchases.<br><br><b>Nobody can help you recover your passphrase, including High Fidelity.</b> Please write it down and store it securely.");
|
||||
answer: qsTr("Your passphrase is used to encrypt your private keys. If you lose your passphrase, you will no longer be able to decrypt your private key file. You will also no longer have access to the contents of your Wallet or My Purchases.<br><br><b>Nobody can help you recover your passphrase, including High Fidelity.</b> Please write it down and store it securely.");
|
||||
}
|
||||
ListElement {
|
||||
isExpanded: false;
|
||||
question: "What is a 'Security Pic'?"
|
||||
answer: qsTr("Your Security Pic is an encrypted image that you selected during Wallet Setup. <b>It acts as an extra layer of Wallet security.</b><br><br>When you see your Security Pic, you know that your actions and data are securely making use of your private keys.<br><br><b>If you don't see your Security Pic on a page that is asking you for your Wallet passphrase, someone untrustworthy may be trying to gain access to your Wallet.</b><br><br>The Pic is stored on your hard drive inside the same file as your private keys.");
|
||||
answer: qsTr("Your Security Pic is an encrypted image that you selected during Wallet Setup. <b>It acts as an extra layer of Wallet security.</b><br><br>When you see your Security Pic, you know that your actions and data are securely making use of your private keys.<br><br><b>If you don't see your Security Pic on a page that is asking you for your Wallet passphrase, someone untrustworthy may be trying to gain access to your Wallet.</b><br><br>The encrypted Pic is stored on your hard drive inside the same file as your private keys.");
|
||||
}
|
||||
ListElement {
|
||||
isExpanded: false;
|
||||
|
|
|
@ -25,8 +25,9 @@ Item {
|
|||
HifiConstants { id: hifi; }
|
||||
|
||||
id: root;
|
||||
z: 998;
|
||||
z: 997;
|
||||
property bool keyboardRaised: false;
|
||||
property bool isPasswordField: false;
|
||||
property string titleBarIcon: "";
|
||||
property string titleBarText: "";
|
||||
|
||||
|
@ -202,6 +203,7 @@ Item {
|
|||
|
||||
onFocusChanged: {
|
||||
root.keyboardRaised = focus;
|
||||
root.isPasswordField = (focus && passphraseField.echoMode === TextInput.Password);
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
|
@ -209,6 +211,7 @@ Item {
|
|||
|
||||
onClicked: {
|
||||
root.keyboardRaised = true;
|
||||
root.isPasswordField = (passphraseField.echoMode === TextInput.Password);
|
||||
mouse.accepted = false;
|
||||
}
|
||||
}
|
||||
|
@ -350,7 +353,7 @@ Item {
|
|||
|
||||
Item {
|
||||
id: keyboardContainer;
|
||||
z: 999;
|
||||
z: 998;
|
||||
visible: keyboard.raised;
|
||||
property bool punctuationMode: false;
|
||||
anchors {
|
||||
|
@ -361,11 +364,13 @@ Item {
|
|||
|
||||
Image {
|
||||
id: lowerKeyboardButton;
|
||||
z: 999;
|
||||
source: "images/lowerKeyboard.png";
|
||||
anchors.horizontalCenter: parent.horizontalCenter;
|
||||
anchors.bottom: keyboard.top;
|
||||
height: 30;
|
||||
width: 120;
|
||||
anchors.right: keyboard.right;
|
||||
anchors.top: keyboard.showMirrorText ? keyboard.top : undefined;
|
||||
anchors.bottom: keyboard.showMirrorText ? undefined : keyboard.bottom;
|
||||
height: 50;
|
||||
width: 60;
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent;
|
||||
|
@ -380,6 +385,7 @@ Item {
|
|||
id: keyboard;
|
||||
raised: HMD.mounted && root.keyboardRaised;
|
||||
numeric: parent.punctuationMode;
|
||||
password: root.isPasswordField;
|
||||
anchors {
|
||||
bottom: parent.bottom;
|
||||
left: parent.left;
|
||||
|
|
|
@ -80,16 +80,18 @@ Item {
|
|||
|
||||
onFocusChanged: {
|
||||
if (focus) {
|
||||
sendSignalToWallet({method: 'walletSetup_raiseKeyboard'});
|
||||
var hidePassword = (currentPassphraseField.echoMode === TextInput.Password);
|
||||
sendSignalToWallet({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword});
|
||||
} else if (!passphraseFieldAgain.focus) {
|
||||
sendSignalToWallet({method: 'walletSetup_lowerKeyboard'});
|
||||
sendSignalToWallet({method: 'walletSetup_lowerKeyboard', isPasswordField: false});
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent;
|
||||
onPressed: {
|
||||
sendSignalToWallet({method: 'walletSetup_raiseKeyboard'});
|
||||
var hidePassword = (currentPassphraseField.echoMode === TextInput.Password);
|
||||
sendSignalToWallet({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword});
|
||||
mouse.accepted = false;
|
||||
}
|
||||
}
|
||||
|
@ -116,16 +118,18 @@ Item {
|
|||
MouseArea {
|
||||
anchors.fill: parent;
|
||||
onPressed: {
|
||||
sendSignalToWallet({method: 'walletSetup_raiseKeyboard'});
|
||||
var hidePassword = (passphraseField.echoMode === TextInput.Password);
|
||||
sendSignalToWallet({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword});
|
||||
mouse.accepted = false;
|
||||
}
|
||||
}
|
||||
|
||||
onFocusChanged: {
|
||||
if (focus) {
|
||||
sendMessageToLightbox({method: 'walletSetup_raiseKeyboard'});
|
||||
var hidePassword = (passphraseField.echoMode === TextInput.Password);
|
||||
sendMessageToLightbox({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword});
|
||||
} else if (!passphraseFieldAgain.focus) {
|
||||
sendMessageToLightbox({method: 'walletSetup_lowerKeyboard'});
|
||||
sendMessageToLightbox({method: 'walletSetup_lowerKeyboard', isPasswordField: false});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -150,16 +154,18 @@ Item {
|
|||
MouseArea {
|
||||
anchors.fill: parent;
|
||||
onPressed: {
|
||||
sendSignalToWallet({method: 'walletSetup_raiseKeyboard'});
|
||||
var hidePassword = (passphraseFieldAgain.echoMode === TextInput.Password);
|
||||
sendSignalToWallet({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword});
|
||||
mouse.accepted = false;
|
||||
}
|
||||
}
|
||||
|
||||
onFocusChanged: {
|
||||
if (focus) {
|
||||
sendMessageToLightbox({method: 'walletSetup_raiseKeyboard'});
|
||||
var hidePassword = (passphraseFieldAgain.echoMode === TextInput.Password);
|
||||
sendMessageToLightbox({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword});
|
||||
} else if (!passphraseField.focus) {
|
||||
sendMessageToLightbox({method: 'walletSetup_lowerKeyboard'});
|
||||
sendMessageToLightbox({method: 'walletSetup_lowerKeyboard', isPasswordField: false});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,13 +25,13 @@ Item {
|
|||
HifiConstants { id: hifi; }
|
||||
|
||||
id: root;
|
||||
property string keyFilePath: "";
|
||||
property string keyFilePath;
|
||||
|
||||
Hifi.QmlCommerce {
|
||||
id: commerce;
|
||||
|
||||
onKeyFilePathIfExistsResult: {
|
||||
keyFilePath = path;
|
||||
root.keyFilePath = path;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -232,6 +232,12 @@ Item {
|
|||
anchors.rightMargin: 55;
|
||||
anchors.bottom: parent.bottom;
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
commerce.getKeyFilePathIfExists();
|
||||
}
|
||||
}
|
||||
|
||||
HiFiGlyphs {
|
||||
id: yourPrivateKeysImage;
|
||||
text: hifi.glyphs.walletKey;
|
||||
|
@ -284,7 +290,17 @@ Item {
|
|||
id: removeHmdContainer;
|
||||
z: 998;
|
||||
visible: false;
|
||||
color: hifi.colors.blueHighlight;
|
||||
|
||||
gradient: Gradient {
|
||||
GradientStop {
|
||||
position: 0.2;
|
||||
color: hifi.colors.baseGrayHighlight;
|
||||
}
|
||||
GradientStop {
|
||||
position: 1.0;
|
||||
color: hifi.colors.baseGrayShadow;
|
||||
}
|
||||
}
|
||||
anchors.fill: backupInstructionsButton;
|
||||
radius: 5;
|
||||
MouseArea {
|
||||
|
@ -320,8 +336,9 @@ Item {
|
|||
height: 40;
|
||||
|
||||
onClicked: {
|
||||
Qt.openUrlExternally("https://www.highfidelity.com/");
|
||||
Qt.openUrlExternally("file:///" + root.keyFilePath.substring(0, root.keyFilePath.lastIndexOf('/')));
|
||||
var keyPath = "file:///" + root.keyFilePath.substring(0, root.keyFilePath.lastIndexOf('/'));
|
||||
Qt.openUrlExternally(keyPath + "/backup_instructions.html");
|
||||
Qt.openUrlExternally(keyPath);
|
||||
removeHmdContainer.visible = true;
|
||||
removeHmdContainerTimer.start();
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ Rectangle {
|
|||
|
||||
property string activeView: "initialize";
|
||||
property bool keyboardRaised: false;
|
||||
property bool isPassword: false;
|
||||
|
||||
Image {
|
||||
anchors.fill: parent;
|
||||
|
@ -165,7 +166,7 @@ Rectangle {
|
|||
WalletSetup {
|
||||
id: walletSetup;
|
||||
visible: root.activeView === "walletSetup";
|
||||
z: 998;
|
||||
z: 997;
|
||||
anchors.fill: parent;
|
||||
|
||||
Connections {
|
||||
|
@ -176,11 +177,15 @@ Rectangle {
|
|||
commerce.getWalletStatus();
|
||||
} else if (msg.referrer === 'purchases') {
|
||||
sendToScript({method: 'goToPurchases'});
|
||||
} else {
|
||||
sendToScript({method: 'goToMarketplaceItemPage', itemId: msg.referrer});
|
||||
}
|
||||
} else if (msg.method === 'walletSetup_raiseKeyboard') {
|
||||
root.keyboardRaised = true;
|
||||
root.isPassword = msg.isPasswordField;
|
||||
} else if (msg.method === 'walletSetup_lowerKeyboard') {
|
||||
root.keyboardRaised = false;
|
||||
root.isPassword = msg.isPasswordField;
|
||||
} else {
|
||||
sendToScript(msg);
|
||||
}
|
||||
|
@ -190,7 +195,7 @@ Rectangle {
|
|||
PassphraseChange {
|
||||
id: passphraseChange;
|
||||
visible: root.activeView === "passphraseChange";
|
||||
z: 998;
|
||||
z: 997;
|
||||
anchors.top: titleBarContainer.bottom;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
|
@ -200,6 +205,7 @@ Rectangle {
|
|||
onSendSignalToWallet: {
|
||||
if (msg.method === 'walletSetup_raiseKeyboard') {
|
||||
root.keyboardRaised = true;
|
||||
root.isPassword = msg.isPasswordField;
|
||||
} else if (msg.method === 'walletSetup_lowerKeyboard') {
|
||||
root.keyboardRaised = false;
|
||||
} else if (msg.method === 'walletSecurity_changePassphraseCancelled') {
|
||||
|
@ -215,7 +221,7 @@ Rectangle {
|
|||
SecurityImageChange {
|
||||
id: securityImageChange;
|
||||
visible: root.activeView === "securityImageChange";
|
||||
z: 998;
|
||||
z: 997;
|
||||
anchors.top: titleBarContainer.bottom;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
|
@ -283,7 +289,7 @@ Rectangle {
|
|||
Connections {
|
||||
onSendSignalToParent: {
|
||||
if (msg.method === "authSuccess") {
|
||||
root.activeView = "walletHome";
|
||||
commerce.getWalletStatus();
|
||||
} else {
|
||||
sendToScript(msg);
|
||||
}
|
||||
|
@ -651,7 +657,7 @@ Rectangle {
|
|||
|
||||
Item {
|
||||
id: keyboardContainer;
|
||||
z: 999;
|
||||
z: 998;
|
||||
visible: keyboard.raised;
|
||||
property bool punctuationMode: false;
|
||||
anchors {
|
||||
|
@ -662,11 +668,13 @@ Rectangle {
|
|||
|
||||
Image {
|
||||
id: lowerKeyboardButton;
|
||||
z: 999;
|
||||
source: "images/lowerKeyboard.png";
|
||||
anchors.horizontalCenter: parent.horizontalCenter;
|
||||
anchors.bottom: keyboard.top;
|
||||
height: 30;
|
||||
width: 120;
|
||||
anchors.right: keyboard.right;
|
||||
anchors.top: keyboard.showMirrorText ? keyboard.top : undefined;
|
||||
anchors.bottom: keyboard.showMirrorText ? undefined : keyboard.bottom;
|
||||
height: 50;
|
||||
width: 60;
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent;
|
||||
|
@ -681,6 +689,7 @@ Rectangle {
|
|||
id: keyboard;
|
||||
raised: HMD.mounted && root.keyboardRaised;
|
||||
numeric: parent.punctuationMode;
|
||||
password: root.isPassword;
|
||||
anchors {
|
||||
bottom: parent.bottom;
|
||||
left: parent.left;
|
||||
|
|
|
@ -43,6 +43,7 @@ Item {
|
|||
|
||||
calculatePendingAndInvalidated();
|
||||
}
|
||||
refreshTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,6 +118,8 @@ Item {
|
|||
historyReceived = false;
|
||||
commerce.balance();
|
||||
commerce.history();
|
||||
} else {
|
||||
refreshTimer.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -138,6 +141,17 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: refreshTimer;
|
||||
interval: 4000; // Remove this after demo?
|
||||
onTriggered: {
|
||||
console.log("Refreshing Wallet Home...");
|
||||
historyReceived = false;
|
||||
commerce.balance();
|
||||
commerce.history();
|
||||
}
|
||||
}
|
||||
|
||||
// Recent Activity
|
||||
Rectangle {
|
||||
id: recentActivityContainer;
|
||||
|
@ -164,7 +178,7 @@ Item {
|
|||
anchors.top: parent.top;
|
||||
anchors.topMargin: 26;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 30;
|
||||
anchors.leftMargin: 20;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 30;
|
||||
height: 30;
|
||||
|
@ -299,10 +313,14 @@ Item {
|
|||
//
|
||||
|
||||
function getFormattedDate(timestamp) {
|
||||
function addLeadingZero(n) {
|
||||
return n < 10 ? '0' + n : '' + n;
|
||||
}
|
||||
|
||||
var a = new Date(timestamp);
|
||||
var year = a.getFullYear();
|
||||
var month = a.getMonth();
|
||||
var day = a.getDate();
|
||||
var month = addLeadingZero(a.getMonth());
|
||||
var day = addLeadingZero(a.getDate());
|
||||
var hour = a.getHours();
|
||||
var drawnHour = hour;
|
||||
if (hour === 0) {
|
||||
|
@ -310,14 +328,15 @@ Item {
|
|||
} else if (hour > 12) {
|
||||
drawnHour -= 12;
|
||||
}
|
||||
drawnHour = addLeadingZero(drawnHour);
|
||||
|
||||
var amOrPm = "AM";
|
||||
if (hour >= 12) {
|
||||
amOrPm = "PM";
|
||||
}
|
||||
|
||||
var min = a.getMinutes();
|
||||
var sec = a.getSeconds();
|
||||
var min = addLeadingZero(a.getMinutes());
|
||||
var sec = addLeadingZero(a.getSeconds());
|
||||
return year + '-' + month + '-' + day + '<br>' + drawnHour + ':' + min + amOrPm;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ Item {
|
|||
property string lastPage;
|
||||
property bool hasShownSecurityImageTip: false;
|
||||
property string referrer;
|
||||
property string keyFilePath;
|
||||
|
||||
Image {
|
||||
anchors.fill: parent;
|
||||
|
@ -58,7 +59,7 @@ Item {
|
|||
}
|
||||
|
||||
onKeyFilePathIfExistsResult: {
|
||||
keyFilePath.text = path;
|
||||
root.keyFilePath = path;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -608,7 +609,7 @@ Item {
|
|||
anchors.fill: parent;
|
||||
|
||||
RalewaySemiBold {
|
||||
id: keyFilePathText;
|
||||
id: keyFilePathHelperText;
|
||||
text: "Private Key File Location:";
|
||||
size: 18;
|
||||
anchors.top: parent.top;
|
||||
|
@ -627,7 +628,7 @@ Item {
|
|||
colorScheme: hifi.colorSchemes.dark;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 30;
|
||||
anchors.top: keyFilePathText.bottom;
|
||||
anchors.top: keyFilePathHelperText.bottom;
|
||||
anchors.topMargin: 8;
|
||||
height: 24;
|
||||
width: height;
|
||||
|
@ -643,11 +644,12 @@ Item {
|
|||
}
|
||||
|
||||
onClicked: {
|
||||
Qt.openUrlExternally("file:///" + keyFilePath.text.substring(0, keyFilePath.text.lastIndexOf('/')));
|
||||
Qt.openUrlExternally("file:///" + keyFilePath.substring(0, keyFilePath.lastIndexOf('/')));
|
||||
}
|
||||
}
|
||||
RalewayRegular {
|
||||
id: keyFilePath;
|
||||
id: keyFilePathText;
|
||||
text: root.keyFilePath;
|
||||
size: 18;
|
||||
anchors.top: clipboardButton.top;
|
||||
anchors.left: clipboardButton.right;
|
||||
|
@ -670,20 +672,21 @@ Item {
|
|||
id: openInstructionsButton;
|
||||
color: hifi.buttons.blue;
|
||||
colorScheme: hifi.colorSchemes.dark;
|
||||
anchors.top: keyFilePath.bottom;
|
||||
anchors.top: keyFilePathText.bottom;
|
||||
anchors.topMargin: 30;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 30;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 30;
|
||||
height: 40;
|
||||
text: "Open Instructions for Later";
|
||||
text: "Open Backup Instructions for Later";
|
||||
onClicked: {
|
||||
instructions01Container.visible = false;
|
||||
instructions02Container.visible = true;
|
||||
keysReadyPageFinishButton.visible = true;
|
||||
Qt.openUrlExternally("https://www.highfidelity.com/");
|
||||
Qt.openUrlExternally("file:///" + root.keyFilePath.substring(0, root.keyFilePath.lastIndexOf('/')));
|
||||
var keyPath = "file:///" + root.keyFilePath.substring(0, root.keyFilePath.lastIndexOf('/'));
|
||||
Qt.openUrlExternally(keyPath + "/backup_instructions.html");
|
||||
Qt.openUrlExternally(keyPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Before Width: | Height: | Size: 721 B After Width: | Height: | Size: 1.2 KiB |