Merge pull request #16294 from RebeccaStankus/friction

First Time User Experience Project
This commit is contained in:
Zach Fox 2019-10-15 14:56:25 -07:00 committed by GitHub
commit 1527bf2e11
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 1075 additions and 73 deletions

View file

@ -9,6 +9,7 @@
//
import QtQuick 2.10
import QtQuick.Layouts 1.3
import "../simplifiedConstants" as SimplifiedConstants
import "../simplifiedControls" as SimplifiedControls
import "./components" as AvatarAppComponents
@ -79,7 +80,11 @@ Rectangle {
errorText.text = "There was a problem while retrieving your inventory. " +
"Please try closing and re-opening the Avatar app.\n\nInventory status: " + result.status + "\nMessage: " + result.message;
} else if (result.data && result.data.assets && result.data.assets.length === 0 && avatarAppInventoryModel.count === 0) {
errorText.text = "You have not created any avatars yet! Create an avatar with the Avatar Creator, then close and re-open the Avatar App."
emptyInventoryContainer.visible = true;
}
if (Settings.getValue("simplifiedUI/debugFTUE", 0) === 4) {
emptyInventoryContainer.visible = true;
}
avatarAppInventoryModel.handlePage(result.status !== "success" && result.message, result);
@ -140,8 +145,95 @@ Rectangle {
anchors.rightMargin: 24
}
Item {
id: emptyInventoryContainer
visible: false
anchors.top: displayNameHeader.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
Flickable {
id: emptyInventoryFlickable
anchors.fill: parent
contentWidth: parent.width
contentHeight: emptyInventoryLayout.height
clip: true
ColumnLayout {
id: emptyInventoryLayout
anchors.top: parent.top
anchors.left: parent.left
anchors.leftMargin: 26
anchors.right: parent.right
anchors.rightMargin: 26
spacing: 0
HifiStylesUit.GraphikSemiBold {
text: "Stand out from the crowd!"
Layout.preferredWidth: parent.width
Layout.preferredHeight: paintedHeight
Layout.topMargin: 16
size: 28
color: simplifiedUI.colors.text.white
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.Wrap
}
HifiStylesUit.GraphikRegular {
text: "Create your custom avatar."
Layout.preferredWidth: parent.width
Layout.preferredHeight: paintedHeight
Layout.topMargin: 2
size: 18
wrapMode: Text.Wrap
color: simplifiedUI.colors.text.white
horizontalAlignment: Text.AlignHCenter
}
Image {
id: avatarImage;
source: "images/avatarProfilePic.png"
Layout.preferredWidth: parent.width
Layout.preferredHeight: 450
Layout.alignment: Qt.AlignHCenter
mipmap: true
fillMode: Image.PreserveAspectFit
}
Image {
source: "images/qrCode.jpg"
Layout.preferredWidth: 190
Layout.preferredHeight: 190
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: -160
mipmap: true
fillMode: Image.PreserveAspectFit
}
HifiStylesUit.GraphikSemiBold {
text: "Scan for Mobile App"
Layout.preferredWidth: parent.width
Layout.preferredHeight: paintedHeight
Layout.topMargin: 12
size: 28
color: simplifiedUI.colors.text.white
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.Wrap
}
}
}
SimplifiedControls.VerticalScrollBar {
parent: emptyInventoryFlickable
}
}
Item {
id: avatarInfoTextContainer
visible: !emptyInventoryContainer.visible
width: parent.implicitWidth
height: childrenRect.height
anchors.top: displayNameHeader.bottom
@ -164,7 +256,7 @@ Rectangle {
id: yourAvatarsSubtitle
text: "These are the avatars that you've created and uploaded via the Avatar Creator."
width: parent.width
wrapMode: Text.WordWrap
wrapMode: Text.Wrap
anchors.top: yourAvatarsTitle.bottom
anchors.topMargin: 6
verticalAlignment: TextInput.AlignVCenter
@ -208,9 +300,10 @@ Rectangle {
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
visible: !emptyInventoryContainer.visible
AnimatedImage {
visible: !inventoryContentsList.visible && !errorText.visible
visible: !(inventoryContentsList.visible || errorText.visible)
anchors.centerIn: parent
width: 72
height: width
@ -271,6 +364,8 @@ Rectangle {
return;
}
}
root.avatarPreviewUrl = "../../images/defaultAvatar.svg";
}
function fromScript(message) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

View file

@ -54,8 +54,8 @@ Rectangle {
if ((MyAvatar.skeletonModelURL.indexOf("defaultAvatar") > -1 || MyAvatar.skeletonModelURL.indexOf("fst") === -1) &&
topBarInventoryModel.count > 0) {
Settings.setValue("simplifiedUI/alreadyAutoSelectedAvatar", true);
MyAvatar.useFullAvatarURL = topBarInventoryModel.get(0).download_url;
Settings.setValue("simplifiedUI/alreadyAutoSelectedAvatarFromInventory", true);
MyAvatar.useFullAvatarURL(topBarInventoryModel.get(0).download_url);
}
}
}
@ -71,7 +71,7 @@ Rectangle {
if (isLoggedIn) {
Commerce.getWalletStatus();
} else {
// Show some error to the user
// Show some error to the user in the UI?
}
}
@ -113,12 +113,68 @@ Rectangle {
topBarInventoryModel.getNextPage();
} else {
inventoryFullyReceived = true;
var scriptExecutionCount = Settings.getValue("simplifiedUI/SUIScriptExecutionCount");
var currentAvatarURL = MyAvatar.skeletonModelURL;
var currentAvatarURLContainsDefaultAvatar = currentAvatarURL.indexOf("defaultAvatar") > -1;
var currentAvatarURLContainsFST = currentAvatarURL.indexOf("fst") > -1;
var currentAvatarURLContainsSimplifiedAvatar = currentAvatarURL.indexOf("simplifiedAvatar") > -1;
var alreadyAutoSelectedAvatarFromInventory = Settings.getValue("simplifiedUI/alreadyAutoSelectedAvatarFromInventory", false);
var userHasValidAvatarInInventory = topBarInventoryModel.count > 0 &&
topBarInventoryModel.get(0).download_url.indexOf(".fst") > -1;
var simplifiedAvatarPrefix = "https://content.highfidelity.com/Experiences/Releases/simplifiedUI/simplifiedFTUE/avatars/simplifiedAvatar_";
var simplifiedAvatarColors = ["Blue", "Cyan", "Green", "Magenta", "Red"];
var simplifiedAvatarSuffix = "/avatar.fst";
// If we have an avatar in our inventory AND we haven't already auto-selected an avatar...
if ((!Settings.getValue("simplifiedUI/alreadyAutoSelectedAvatar", false) ||
MyAvatar.skeletonModelURL.indexOf("defaultAvatar") > -1 || MyAvatar.skeletonModelURL.indexOf("fst") === -1) && topBarInventoryModel.count > 0) {
Settings.setValue("simplifiedUI/alreadyAutoSelectedAvatar", true);
MyAvatar.skeletonModelURL = topBarInventoryModel.get(0).download_url;
// Use `Settings.setValue("simplifiedUI/debugFTUE", 0);` to turn off FTUE Debug Mode.
// Use `Settings.setValue("simplifiedUI/debugFTUE", 1);` to debug FTUE Screen 1.
// Use `Settings.setValue("simplifiedUI/debugFTUE", 2);` to debug FTUE Screen 2.
// Use `Settings.setValue("simplifiedUI/debugFTUE", 3);` to debug FTUE Screen 3.
// Use `Settings.setValue("simplifiedUI/debugFTUE", 4);` to force the UI to show what would happen if the user had an empty Inventory.
var debugFTUE = Settings.getValue("simplifiedUI/debugFTUE", 0);
if (debugFTUE === 1 || debugFTUE === 2) {
scriptExecutionCount = 1;
currentAvatarURLContainsDefaultAvatar = true;
if (debugFTUE === 1) {
userHasValidAvatarInInventory = false;
currentAvatarURLContainsSimplifiedAvatar = false;
}
} else if (debugFTUE === 3) {
scriptExecutionCount = 2;
currentAvatarURLContainsDefaultAvatar = false;
currentAvatarURLContainsSimplifiedAvatar = true;
}
// If we have never auto-selected and the user is still using a default avatar or if the current avatar is not valid (fst), or if
// the current avatar is the old default (Woody), use top avatar from inventory or one of the new defaults.
// If the current avatar URL is invalid, OR the user is using the "default avatar" (Woody)...
if (!currentAvatarURLContainsFST || currentAvatarURLContainsDefaultAvatar) {
// If the user has a valid avatar in their inventory...
if (userHasValidAvatarInInventory) {
// ...use the first avatar in the user's inventory.
MyAvatar.useFullAvatarURL(topBarInventoryModel.get(0).download_url);
Settings.setValue("simplifiedUI/alreadyAutoSelectedAvatarFromInventory", true);
// Else if the user isn't wearing a "Simplified Avatar"
} else if (!currentAvatarURLContainsSimplifiedAvatar) {
// ...assign to the user a new "Simplified Avatar" (i.e. a simple avatar of random color)
var avatarColor = simplifiedAvatarColors[Math.floor(Math.random() * simplifiedAvatarColors.length)];
var simplifiedAvatarModelURL = simplifiedAvatarPrefix + avatarColor + simplifiedAvatarSuffix;
MyAvatar.useFullAvatarURL(simplifiedAvatarModelURL);
currentAvatarURLContainsSimplifiedAvatar = true;
}
}
if (scriptExecutionCount === 1) {
sendToScript({
"source": "SimplifiedTopBar.qml",
"method": "displayInitialLaunchWindow"
});
} else if (scriptExecutionCount === 2 && currentAvatarURLContainsSimplifiedAvatar) {
sendToScript({
"source": "SimplifiedTopBar.qml",
"method": "displaySecondLaunchWindow"
});
}
}
}
@ -556,7 +612,7 @@ Rectangle {
}
function updatePreviewUrl() {
function updatePreviewUrl() {
var previewUrl = "";
var downloadUrl = "";
for (var i = 0; i < topBarInventoryModel.count; ++i) {
@ -570,6 +626,8 @@ Rectangle {
return;
}
}
avatarButtonImage.source = "../images/defaultAvatar.svg";
}

View file

@ -52,6 +52,21 @@ static const QVariantMap DOCK_AREA {
{ "RIGHT", DockArea::RIGHT }
};
/**jsdoc
* The possible "relative position anchors" of an <code>InteractiveWindow</code>. Used when defining the `relativePosition` property of an `InteractiveWindow`.
* @typedef {object} InteractiveWindow.RelativePositionAnchors
* @property {InteractiveWindow.RelativePositionAnchor} TOP_LEFT - Specifies that the `relativePosition` of the `InteractiveWindow` will be offset from the top left of the Interface window.
* @property {InteractiveWindow.RelativePositionAnchor} TOP_RIGHT - Specifies that the `relativePosition` of the `InteractiveWindow` will be offset from the top right of the Interface window.
* @property {InteractiveWindow.RelativePositionAnchor} BOTTOM_RIGHT - Specifies that the `relativePosition` of the `InteractiveWindow` will be offset from the bottom right of the Interface window.
* @property {InteractiveWindow.RelativePositionAnchor} BOTTOM_LEFT - Specifies that the `relativePosition` of the `InteractiveWindow` will be offset from the bottom left of the Interface window.
*/
static const QVariantMap RELATIVE_POSITION_ANCHOR {
{ "TOP_LEFT", RelativePositionAnchor::TOP_LEFT },
{ "TOP_RIGHT", RelativePositionAnchor::TOP_RIGHT },
{ "BOTTOM_RIGHT", RelativePositionAnchor::BOTTOM_RIGHT },
{ "BOTTOM_LEFT", RelativePositionAnchor::BOTTOM_LEFT }
};
DesktopScriptingInterface::DesktopScriptingInterface(QObject* parent, bool restricted)
: QObject(parent), _restricted(restricted) { }
@ -99,6 +114,10 @@ QVariantMap DesktopScriptingInterface::getDockArea() {
return DOCK_AREA;
}
QVariantMap DesktopScriptingInterface::getRelativePositionAnchor() {
return RELATIVE_POSITION_ANCHOR;
}
void DesktopScriptingInterface::setHUDAlpha(float alpha) {
qApp->getApplicationCompositor().setAlpha(alpha);
}

View file

@ -42,6 +42,9 @@
* @property {InteractiveWindow.DockAreas} DockArea - The possible docking locations of an {@link InteractiveWindow}: top,
* bottom, left, or right of the Interface window.
* <em>Read-only.</em>
* @property {InteractiveWindow.RelativePositionAnchors} RelativePositionAnchor - The possible "relative position anchors" for an {@link InteractiveWindow}: top left,
* top right, bottom right, or bottom left of the Interface window.
* <em>Read-only.</em>
*/
class DesktopScriptingInterface : public QObject, public Dependency {
Q_OBJECT
@ -50,6 +53,7 @@ class DesktopScriptingInterface : public QObject, public Dependency {
Q_PROPERTY(QVariantMap PresentationMode READ getPresentationMode CONSTANT FINAL)
Q_PROPERTY(QVariantMap DockArea READ getDockArea CONSTANT FINAL)
Q_PROPERTY(QVariantMap RelativePositionAnchor READ getRelativePositionAnchor CONSTANT FINAL)
Q_PROPERTY(int ALWAYS_ON_TOP READ flagAlwaysOnTop CONSTANT FINAL)
Q_PROPERTY(int CLOSE_BUTTON_HIDES READ flagCloseButtonHides CONSTANT FINAL)
@ -106,7 +110,7 @@ private:
Q_INVOKABLE InteractiveWindowPointer createWindowOnThread(const QString& sourceUrl, const QVariantMap& properties, QThread* targetThread);
static QVariantMap getDockArea();
static QVariantMap getRelativePositionAnchor();
Q_INVOKABLE static QVariantMap getPresentationMode();
const bool _restricted;
};

View file

@ -39,6 +39,9 @@ static const char* const ADDITIONAL_FLAGS_PROPERTY = "additionalFlags";
static const char* const OVERRIDE_FLAGS_PROPERTY = "overrideFlags";
static const char* const SOURCE_PROPERTY = "source";
static const char* const TITLE_PROPERTY = "title";
static const char* const RELATIVE_POSITION_ANCHOR_PROPERTY = "relativePositionAnchor";
static const char* const RELATIVE_POSITION_PROPERTY = "relativePosition";
static const char* const IS_FULL_SCREEN_WINDOW = "isFullScreenWindow";
static const char* const POSITION_PROPERTY = "position";
static const char* const INTERACTIVE_WINDOW_POSITION_PROPERTY = "interactiveWindowPosition";
static const char* const SIZE_PROPERTY = "size";
@ -112,6 +115,14 @@ void InteractiveWindow::forwardKeyReleaseEvent(int key, int modifiers) {
QCoreApplication::postEvent(QCoreApplication::instance(), event);
}
void InteractiveWindow::onMainWindowGeometryChanged(QRect geometry) {
if (_isFullScreenWindow) {
repositionAndResizeFullScreenWindow();
} else {
setPositionUsingRelativePositionAndAnchor(geometry);
}
}
void InteractiveWindow::emitMainWindowResizeEvent() {
emit qApp->getWindow()->windowGeometryChanged(qApp->getWindow()->geometry());
}
@ -184,22 +195,32 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap
*/
if (nativeWindowInfo.contains(DOCK_AREA_PROPERTY)) {
DockArea dockedArea = (DockArea) nativeWindowInfo[DOCK_AREA_PROPERTY].toInt();
int tempWidth = 0;
int tempHeight = 0;
switch (dockedArea) {
case DockArea::TOP:
dockArea = Qt::TopDockWidgetArea;
_dockWidget->setFixedHeight(windowSize.height());
tempHeight = windowSize.height();
_dockWidget->setFixedHeight(tempHeight);
qApp->getWindow()->setDockedWidgetRelativePositionOffset(QSize(0, -tempHeight));
break;
case DockArea::BOTTOM:
dockArea = Qt::BottomDockWidgetArea;
_dockWidget->setFixedHeight(windowSize.height());
tempHeight = windowSize.height();
_dockWidget->setFixedHeight(tempHeight);
qApp->getWindow()->setDockedWidgetRelativePositionOffset(QSize(0, tempHeight));
break;
case DockArea::LEFT:
dockArea = Qt::LeftDockWidgetArea;
_dockWidget->setFixedWidth(windowSize.width());
tempWidth = windowSize.width();
_dockWidget->setFixedWidth(tempWidth);
qApp->getWindow()->setDockedWidgetRelativePositionOffset(QSize(-tempWidth, 0));
break;
case DockArea::RIGHT:
dockArea = Qt::RightDockWidgetArea;
_dockWidget->setFixedWidth(windowSize.width());
tempWidth = windowSize.width();
_dockWidget->setFixedWidth(tempWidth);
qApp->getWindow()->setDockedWidgetRelativePositionOffset(QSize(tempWidth, 0));
break;
default:
@ -255,6 +276,9 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap
if (properties.contains(TITLE_PROPERTY)) {
object->setProperty(TITLE_PROPERTY, properties[TITLE_PROPERTY].toString());
}
if (properties.contains(VISIBLE_PROPERTY)) {
object->setProperty(VISIBLE_PROPERTY, properties[INTERACTIVE_WINDOW_VISIBLE_PROPERTY].toBool());
}
if (properties.contains(SIZE_PROPERTY)) {
const auto size = vec2FromVariant(properties[SIZE_PROPERTY]);
object->setProperty(INTERACTIVE_WINDOW_SIZE_PROPERTY, QSize(size.x, size.y));
@ -263,8 +287,21 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap
const auto position = vec2FromVariant(properties[POSITION_PROPERTY]);
object->setProperty(INTERACTIVE_WINDOW_POSITION_PROPERTY, QPointF(position.x, position.y));
}
if (properties.contains(VISIBLE_PROPERTY)) {
object->setProperty(VISIBLE_PROPERTY, properties[INTERACTIVE_WINDOW_VISIBLE_PROPERTY].toBool());
if (properties.contains(RELATIVE_POSITION_ANCHOR_PROPERTY)) {
_relativePositionAnchor = static_cast<RelativePositionAnchor>(properties[RELATIVE_POSITION_ANCHOR_PROPERTY].toInt());
}
if (properties.contains(RELATIVE_POSITION_PROPERTY)) {
_relativePosition = vec2FromVariant(properties[RELATIVE_POSITION_PROPERTY]);
setPositionUsingRelativePositionAndAnchor(qApp->getWindow()->geometry());
}
if (properties.contains(IS_FULL_SCREEN_WINDOW)) {
_isFullScreenWindow = properties[IS_FULL_SCREEN_WINDOW].toBool();
}
if (_isFullScreenWindow) {
QRect geo = qApp->getWindow()->geometry();
object->setProperty(INTERACTIVE_WINDOW_POSITION_PROPERTY, QPointF(geo.x(), geo.y()));
object->setProperty(INTERACTIVE_WINDOW_SIZE_PROPERTY, QSize(geo.width(), geo.height()));
}
// The qmlToScript method handles the thread-safety of this call. Because the QVariant argument
@ -288,6 +325,8 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap
connect(object, SIGNAL(interactiveWindowVisibleChanged()), this, SLOT(parentNativeWindowToMainWindow()), Qt::QueuedConnection);
connect(object, SIGNAL(presentationModeChanged()), this, SLOT(parentNativeWindowToMainWindow()), Qt::QueuedConnection);
#endif
connect(qApp->getWindow(), &MainWindow::windowGeometryChanged, this, &InteractiveWindow::onMainWindowGeometryChanged, Qt::QueuedConnection);
QUrl sourceURL{ sourceUrl };
// If the passed URL doesn't correspond to a known scheme, assume it's a local file path
@ -414,6 +453,68 @@ void InteractiveWindow::setPosition(const glm::vec2& position) {
}
}
RelativePositionAnchor InteractiveWindow::getRelativePositionAnchor() const {
return _relativePositionAnchor;
}
void InteractiveWindow::setRelativePositionAnchor(const RelativePositionAnchor& relativePositionAnchor) {
_relativePositionAnchor = relativePositionAnchor;
setPositionUsingRelativePositionAndAnchor(qApp->getWindow()->geometry());
}
glm::vec2 InteractiveWindow::getRelativePosition() const {
return _relativePosition;
}
void InteractiveWindow::setRelativePosition(const glm::vec2& relativePosition) {
_relativePosition = relativePosition;
setPositionUsingRelativePositionAndAnchor(qApp->getWindow()->geometry());
}
void InteractiveWindow::setPositionUsingRelativePositionAndAnchor(const QRect& mainWindowGeometry) {
RelativePositionAnchor relativePositionAnchor = getRelativePositionAnchor();
glm::vec2 relativePosition = getRelativePosition();
glm::vec2 newPosition;
switch (relativePositionAnchor) {
case RelativePositionAnchor::TOP_LEFT:
newPosition.x = mainWindowGeometry.x() + relativePosition.x;
newPosition.y = mainWindowGeometry.y() + relativePosition.y;
break;
case RelativePositionAnchor::TOP_RIGHT:
newPosition.x = mainWindowGeometry.x() + mainWindowGeometry.width() - relativePosition.x;
newPosition.y = mainWindowGeometry.y() + relativePosition.y;
break;
case RelativePositionAnchor::BOTTOM_RIGHT:
newPosition.x = mainWindowGeometry.x() + mainWindowGeometry.width() - relativePosition.x;
newPosition.y = mainWindowGeometry.y() + mainWindowGeometry.height() - relativePosition.y;
break;
case RelativePositionAnchor::BOTTOM_LEFT:
newPosition.x = mainWindowGeometry.x() + relativePosition.x;
newPosition.y = mainWindowGeometry.y() + mainWindowGeometry.height() - relativePosition.y;
break;
}
// Make sure we include the dimensions of the docked widget!
QSize dockedWidgetRelativePositionOffset = qApp->getWindow()->getDockedWidgetRelativePositionOffset();
newPosition.x = newPosition.x + dockedWidgetRelativePositionOffset.width();
newPosition.y = newPosition.y + dockedWidgetRelativePositionOffset.height();
if (_qmlWindowProxy) {
QMetaObject::invokeMethod(_qmlWindowProxy.get(), "writeProperty", Q_ARG(QString, INTERACTIVE_WINDOW_POSITION_PROPERTY),
Q_ARG(QVariant, QPointF(newPosition.x, newPosition.y)));
}
setPosition(newPosition);
}
void InteractiveWindow::repositionAndResizeFullScreenWindow() {
QRect windowGeometry = qApp->getWindow()->geometry();
setPosition(glm::vec2(windowGeometry.x(), windowGeometry.y()));
setSize(glm::vec2(windowGeometry.width(), windowGeometry.height()));
}
glm::vec2 InteractiveWindow::getSize() const {
if (!_qmlWindowProxy) {
return {};

View file

@ -89,6 +89,14 @@ namespace InteractiveWindowEnums {
RIGHT
};
Q_ENUM_NS(DockArea);
enum RelativePositionAnchor {
TOP_LEFT,
TOP_RIGHT,
BOTTOM_RIGHT,
BOTTOM_LEFT
};
Q_ENUM_NS(RelativePositionAnchor);
}
using namespace InteractiveWindowEnums;
@ -121,6 +129,8 @@ class InteractiveWindow : public QObject {
Q_PROPERTY(QString title READ getTitle WRITE setTitle)
Q_PROPERTY(glm::vec2 position READ getPosition WRITE setPosition)
Q_PROPERTY(RelativePositionAnchor relativePositionAnchor READ getRelativePositionAnchor WRITE setRelativePositionAnchor)
Q_PROPERTY(glm::vec2 relativePosition READ getRelativePosition WRITE setRelativePosition)
Q_PROPERTY(glm::vec2 size READ getSize WRITE setSize)
Q_PROPERTY(bool visible READ isVisible WRITE setVisible)
Q_PROPERTY(int presentationMode READ getPresentationMode WRITE setPresentationMode)
@ -136,6 +146,21 @@ private:
Q_INVOKABLE glm::vec2 getPosition() const;
Q_INVOKABLE void setPosition(const glm::vec2& position);
RelativePositionAnchor _relativePositionAnchor{ RelativePositionAnchor::TOP_LEFT };
Q_INVOKABLE RelativePositionAnchor getRelativePositionAnchor() const;
Q_INVOKABLE void setRelativePositionAnchor(const RelativePositionAnchor& position);
// This "relative position" is relative to the "relative position anchor" and excludes the window frame.
// This position will ALWAYS include the geometry of a docked widget, if one is present.
glm::vec2 _relativePosition{ 0.0f, 0.0f };
Q_INVOKABLE glm::vec2 getRelativePosition() const;
Q_INVOKABLE void setRelativePosition(const glm::vec2& position);
Q_INVOKABLE void setPositionUsingRelativePositionAndAnchor(const QRect& mainWindowGeometry);
bool _isFullScreenWindow{ false };
Q_INVOKABLE void repositionAndResizeFullScreenWindow();
Q_INVOKABLE glm::vec2 getSize() const;
Q_INVOKABLE void setSize(const glm::vec2& size);
@ -320,6 +345,7 @@ protected slots:
void forwardKeyPressEvent(int key, int modifiers);
void forwardKeyReleaseEvent(int key, int modifiers);
void emitMainWindowResizeEvent();
void onMainWindowGeometryChanged(QRect geometry);
private:
std::shared_ptr<QmlWindowProxy> _qmlWindowProxy;

View file

@ -24,6 +24,10 @@ public:
~MainWindow();
static QWindow* findMainWindow();
// This offset is used for positioning children window relative to the main window.
void setDockedWidgetRelativePositionOffset(const QSize& newOffset) { _dockedWidgetRelativePositionOffset.setWidth(newOffset.width()); _dockedWidgetRelativePositionOffset.setHeight(newOffset.height()); }
QSize getDockedWidgetRelativePositionOffset() { return _dockedWidgetRelativePositionOffset; }
public slots:
void restoreGeometry();
void saveGeometry();
@ -46,6 +50,7 @@ protected:
private:
Setting::Handle<QRect> _windowGeometry;
Setting::Handle<int> _windowState;
QSize _dockedWidgetRelativePositionOffset{ 0, 0 };
};
#endif /* defined(__hifi__MainWindow__) */

View file

@ -444,17 +444,9 @@ function updateEmoteIndicatorIcon(iconURL) {
}
function onGeometryChanged(rect) {
updateEmoteAppBarPosition();
}
function onWindowMinimizedChanged(isMinimized) {
if (isMinimized) {
handleEmoteIndicatorVisibleChanged(false);
} else if (!HMD.active) {
handleEmoteIndicatorVisibleChanged(true);
}
isWindowMinimized = isMinimized;
maybeChangeEmoteIndicatorVisibility(!isMinimized);
}
@ -539,10 +531,11 @@ function showEmoteAppBar() {
x: EMOTE_APP_BAR_WIDTH_PX,
y: EMOTE_APP_BAR_HEIGHT_PX
},
position: {
x: Window.x + EMOTE_APP_BAR_LEFT_MARGIN,
y: Window.y + Window.innerHeight - EMOTE_APP_BAR_BOTTOM_MARGIN
relativePosition: {
x: EMOTE_APP_BAR_LEFT_MARGIN,
y: EMOTE_APP_BAR_BOTTOM_MARGIN
},
relativePositionAnchor: Desktop.RelativePositionAnchor.BOTTOM_LEFT,
overrideFlags: EMOTE_APP_BAR_WINDOW_FLAGS
});
@ -550,10 +543,18 @@ function showEmoteAppBar() {
}
function handleEmoteIndicatorVisibleChanged(shouldBeVisible) {
if (shouldBeVisible && !emoteAppBarWindow) {
// There is currently no property in the Window Scripting Interface to determine
// whether the Interface window is currently minimized. This feels like an oversight.
// We should add that functionality to the Window Scripting Interface, and remove `isWindowMinimized` below.
var isWindowMinimized = false;
function maybeChangeEmoteIndicatorVisibility(desiredVisibility) {
if (isWindowMinimized || HMD.active) {
desiredVisibility = false;
}
if (desiredVisibility && !emoteAppBarWindow) {
showEmoteAppBar();
} else if (emoteAppBarWindow) {
} else if (!desiredVisibility && emoteAppBarWindow) {
emoteAppBarWindow.fromQml.disconnect(onMessageFromEmoteAppBar);
emoteAppBarWindow.close();
emoteAppBarWindow = false;
@ -561,23 +562,25 @@ function handleEmoteIndicatorVisibleChanged(shouldBeVisible) {
}
function handleFTUEScreensVisibilityChanged(ftueScreenVisible) {
maybeChangeEmoteIndicatorVisibility(!ftueScreenVisible);
}
function onDisplayModeChanged(isHMDMode) {
reactionsBegun.forEach(function(react) {
endReactionWrapper(react);
});
if (isHMDMode) {
handleEmoteIndicatorVisibleChanged(false);
} else {
handleEmoteIndicatorVisibleChanged(true);
}
maybeChangeEmoteIndicatorVisibility(!isHMDMode);
}
var emojiAPI = Script.require("./emojiApp/simplifiedEmoji.js?" + Date.now());
var emojiAPI = Script.require("./emojiApp/simplifiedEmoji.js");
var keyPressSignalsConnected = false;
var emojiCodeMap;
var customEmojiCodeMap;
var _this;
function setup() {
deleteOldReticles();
@ -605,16 +608,25 @@ function setup() {
}, {});
Window.minimizedChanged.connect(onWindowMinimizedChanged);
Window.geometryChanged.connect(onGeometryChanged);
HMD.displayModeChanged.connect(onDisplayModeChanged);
getSounds();
handleEmoteIndicatorVisibleChanged(true);
maybeChangeEmoteIndicatorVisibility(true);
Controller.keyPressEvent.connect(keyPressHandler);
Controller.keyReleaseEvent.connect(keyReleaseHandler);
keyPressSignalsConnected = true;
Script.scriptEnding.connect(unload);
function Emote() {
_this = this;
}
Emote.prototype = {
handleFTUEScreensVisibilityChanged: handleFTUEScreensVisibilityChanged
};
return new Emote();
}
@ -638,7 +650,6 @@ function unload() {
maybeDeleteRemoteIndicatorTimeout();
Window.minimizedChanged.disconnect(onWindowMinimizedChanged);
Window.geometryChanged.disconnect(onGeometryChanged);
HMD.displayModeChanged.disconnect(onDisplayModeChanged);
if (keyPressSignalsConnected) {
@ -671,7 +682,6 @@ function unload() {
// #region EMOJI_UTILITY
var EMOJI_52_BASE_URL = "../../resources/images/emojis/52px/";
function selectedEmoji(code) {
emojiAPI.addEmoji(code);
// this URL needs to be relative to SimplifiedEmoteIndicator.qml
@ -786,4 +796,6 @@ function toggleEmojiApp() {
// END EMOJI
// *************************************
setup();
var emote = setup();
module.exports = emote;

View file

@ -0,0 +1,350 @@
//
// InitialLaunchWindow.qml
//
// Copyright 2019 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.10
import QtQuick.Controls 2.3
import QtGraphicalEffects 1.0
import QtQuick.Layouts 1.3
import stylesUit 1.0 as HifiStylesUit
import TabletScriptingInterface 1.0
import hifi.simplifiedUI.simplifiedConstants 1.0 as SimplifiedConstants
import hifi.simplifiedUI.simplifiedControls 1.0 as SimplifiedControls
Rectangle {
id: root
color: simplifiedUI.colors.white
anchors.fill: parent
property bool landscapeOrientation: root.width > root.height
SimplifiedConstants.SimplifiedConstants {
id: simplifiedUI
}
Component.onCompleted: {
var debugFTUE = Settings.getValue("simplifiedUI/debugFTUE", 0);
if ((debugFTUE !== 1 &&
(Settings.getValue("simplifiedUI/alreadyAutoSelectedAvatarFromInventory", false) ||
Settings.getValue("simplifiedUI/closedAvatarPageOfInitialLaunchWindow", false))) ||
debugFTUE === 2) {
tempAvatarPageContainer.visible = false;
controlsContainer.visible = true;
}
}
Item {
id: tempAvatarPageContainer
anchors.fill: parent
Item {
id: contentContainer
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: firstPageBottomBarContainer.top
Image {
id: avatarImage
anchors.verticalCenter: parent.verticalCenter
height: Math.max(parent.height - 48, 350)
anchors.left: parent.left
anchors.leftMargin: 12
source: resourceDirectoryUrl + "qml/hifi/simplifiedUI/avatarApp/images/" +
MyAvatar.skeletonModelURL.substring(MyAvatar.skeletonModelURL.indexOf("simplifiedAvatar"), MyAvatar.skeletonModelURL.lastIndexOf("/")) + ".png"
mipmap: true
fillMode: Image.PreserveAspectFit
}
Flickable {
id: textContainer
clip: true
anchors.top: parent.top
anchors.topMargin: 128
anchors.bottom: qrAndInstructionsContainer.top
anchors.bottomMargin: 32
anchors.left: avatarImage.right
anchors.leftMargin: 48
anchors.right: parent.right
contentWidth: width
contentHeight: contentItem.childrenRect.height
interactive: contentHeight > height
HifiStylesUit.RalewayBold {
id: headerText
text: "We know this isn't you..."
color: simplifiedUI.colors.text.black
size: 48
height: paintedHeight
wrapMode: Text.Wrap
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: 16
}
HifiStylesUit.RalewayRegular {
id: descriptionText
anchors.top: headerText.bottom
anchors.topMargin: 10
anchors.left: parent.left
width: Math.min(700, parent.width) - headerText.anchors.rightMargin
height: paintedHeight
text: "...but we've given you this <b>temporary avatar</b> to use " +
"for today. If you see this avatar in-world, walk up and " +
"say hello to other new users!<br><br>" +
"<b>We want you to be you</b> so we've built " +
'<a href="https://www.highfidelity.com/knowledge/virtual-you/">Virtual You</a>, an Avatar Creator ' +
"App. Creating an avatar is as easy as taking a selfie and picking your " +
"outfits! Available now on iOS and Android."
color: simplifiedUI.colors.text.black
size: 22
wrapMode: Text.Wrap
onLinkActivated: {
Qt.openUrlExternally(link);
}
}
}
Item {
id: qrAndInstructionsContainer
anchors.left: avatarImage.right
anchors.leftMargin: 48
anchors.right: parent.right
anchors.rightMargin: 16
anchors.bottom: parent.bottom
height: 130
Image {
id: avatarAppQRCodeImage
source: resourceDirectoryUrl + "qml/hifi/simplifiedUI/avatarApp/images/qrCode.jpg"
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
width: 130
mipmap: true
fillMode: Image.PreserveAspectFit
}
HifiStylesUit.RalewayBold {
id: instructionText
anchors.top: avatarAppQRCodeImage.top
anchors.bottom: avatarAppQRCodeImage.bottom
anchors.left: avatarAppQRCodeImage.right
anchors.leftMargin: 30
anchors.right: parent.right
text: "Use your mobile phone to scan this QR code."
color: simplifiedUI.colors.text.black
size: 22
wrapMode: Text.Wrap
}
}
SimplifiedControls.VerticalScrollBar {
parent: textContainer
visible: parent.contentHeight > parent.height
size: parent.height / parent.contentHeight
}
}
Item {
id: firstPageBottomBarContainer
anchors.left: parent.left
anchors.leftMargin: 32
anchors.right: parent.right
anchors.rightMargin: 32
anchors.bottom: parent.bottom
height: continueLink.height + 48
HifiStylesUit.RalewayBold {
id: continueLink
anchors.centerIn: parent
text: "Continue >"
width: parent.width
height: paintedHeight
color: simplifiedUI.colors.text.lightBlue
opacity: continueMouseArea.containsMouse ? 1.0 : 0.7
size: 36
wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter
MouseArea {
id: continueMouseArea
hoverEnabled: true
anchors.fill: parent
onClicked: {
Tablet.playSound(TabletEnums.ButtonClick);
tempAvatarPageContainer.visible = false;
Settings.setValue("simplifiedUI/closedAvatarPageOfInitialLaunchWindow", true);
controlsContainer.visible = true;
}
}
}
}
}
Item {
id: controlsContainer
visible: false
anchors.fill: parent
HifiStylesUit.RalewayRegular {
id: controlsDescriptionText
text: "Use these avatar controls to<br><b>interact with and move around in your new HQ.</b>"
anchors.top: parent.top
anchors.topMargin: 48
anchors.left: parent.left
anchors.leftMargin: 32
anchors.right: parent.right
anchors.rightMargin: 32
horizontalAlignment: Text.AlignHCenter
height: paintedHeight
color: simplifiedUI.colors.text.black
size: 36
wrapMode: Text.Wrap
}
Item {
anchors.top: controlsDescriptionText.bottom
anchors.topMargin: 16
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: bottomBarContainer.top
GridView {
id: controlsGrid
property int maxColumns: 2
property int idealCellWidth: 361
anchors.fill: parent
clip: true
cellWidth: width / Math.min(Math.floor(width / idealCellWidth), maxColumns)
cellHeight: 225
model: ListModel {
ListElement {
imageHeight: 198
imageSource: "images/walkingControls.png"
}
ListElement {
imageHeight: 193
imageSource: "images/mouseControls.png"
}
ListElement {
imageHeight: 146
imageSource: "images/runJumpControls.png"
}
ListElement {
imageHeight: 96
imageSource: "images/cameraControls.png"
}
}
delegate: Rectangle {
height: GridView.view.cellHeight
width: GridView.view.cellWidth
Image {
anchors.centerIn: parent
width: parent.GridView.view.idealCellWidth
height: model.imageHeight
source: model.imageSource
fillMode: Image.PreserveAspectFit
}
}
}
SimplifiedControls.VerticalScrollBar {
parent: controlsGrid
anchors.topMargin: 96
anchors.bottomMargin: anchors.topMargin
}
}
Item {
id: bottomBarContainer
anchors.left: parent.left
anchors.leftMargin: 32
anchors.right: parent.right
anchors.rightMargin: 32
anchors.bottom: parent.bottom
height: iHaveAGoodGrip.height + learnMoreLink.height + 48
HifiStylesUit.RalewayBold {
id: iHaveAGoodGrip
anchors.centerIn: parent
text: "I've got a good grip on the controls."
width: parent.width
height: paintedHeight
color: simplifiedUI.colors.text.lightBlue
opacity: goodGripMouseArea.containsMouse ? 1.0 : 0.7
size: 36
wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter
MouseArea {
id: goodGripMouseArea
hoverEnabled: true
anchors.fill: parent
onClicked: {
Tablet.playSound(TabletEnums.ButtonClick);
sendToScript({
"source": "InitialLaunchWindow.qml",
"method": "closeInitialLaunchWindow"
});
}
}
}
HifiStylesUit.RalewayBold {
id: learnMoreLink
anchors.left: parent.left
anchors.leftMargin: 16
anchors.top: iHaveAGoodGrip.bottom
anchors.topMargin: 8
text: "Learn more about our controls."
width: paintedWidth
height: paintedHeight
color: simplifiedUI.colors.text.lightBlue
opacity: learnMoreAboutControlsMouseArea.containsMouse ? 1.0 : 0.7
size: 14
wrapMode: Text.Wrap
MouseArea {
id: learnMoreAboutControlsMouseArea
hoverEnabled: true
anchors.fill: parent
onClicked: {
Tablet.playSound(TabletEnums.ButtonClick);
Qt.openUrlExternally("https://www.highfidelity.com/knowledge/get-around");
}
}
}
}
}
Image {
id: topLeftAccentImage
width: 400
height: 180
anchors.left: parent.left
anchors.top: parent.top
source: "images/defaultTopLeft.png"
}
Image {
id: bottomRightAccentImage
width: 80
height: 250
anchors.right: parent.right
anchors.bottom: parent.bottom
source: "images/defaultBottomRight.png"
}
signal sendToScript(var message);
}

View file

@ -0,0 +1,186 @@
//
// SecondLaunchWindow.qml
//
// Copyright 2019 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.10
import QtQuick.Controls 2.3
import QtGraphicalEffects 1.0
import QtQuick.Layouts 1.3
import stylesUit 1.0 as HifiStylesUit
import TabletScriptingInterface 1.0
import hifi.simplifiedUI.simplifiedConstants 1.0 as SimplifiedConstants
import hifi.simplifiedUI.simplifiedControls 1.0 as SimplifiedControls
Rectangle {
id: root
color: simplifiedUI.colors.white
anchors.fill: parent
SimplifiedConstants.SimplifiedConstants {
id: simplifiedUI
}
Item {
id: contentContainer
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: continueLink.top
Image {
id: avatarImage
anchors.verticalCenter: parent.verticalCenter
height: Math.max(parent.height - 48, 350)
anchors.left: parent.left
anchors.leftMargin: 12
source: resourceDirectoryUrl + "qml/hifi/simplifiedUI/avatarApp/images/hero.png"
mipmap: true
fillMode: Image.PreserveAspectFit
}
Item {
anchors.top: parent.top
anchors.topMargin: 196
anchors.bottom: parent.bottom
anchors.bottomMargin: 32
anchors.left: avatarImage.right
anchors.leftMargin: 48
anchors.right: parent.right
Flickable {
id: textContainer
clip: true
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
width: Math.min(700, parent.width)
contentWidth: width
contentHeight: contentItem.childrenRect.height
interactive: contentHeight > height
HifiStylesUit.RalewayBold {
id: headerText
text: "Stand out from the crowd!"
color: simplifiedUI.colors.text.black
size: 48
height: paintedHeight
wrapMode: Text.Wrap
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: 16
}
HifiStylesUit.RalewayRegular {
id: descriptionText
anchors.top: headerText.bottom
anchors.topMargin: 10
anchors.left: parent.left
width: parent.width - headerText.anchors.rightMargin
height: paintedHeight
text: "You can create and upload custom avatars from our Avatar Creator App. " +
"It's as easy as taking a selfie.<br>Available now on iOS and Android Platforms."
color: simplifiedUI.colors.text.black
size: 22
wrapMode: Text.Wrap
}
Item {
id: qrAndInstructionsContainer
anchors.top: descriptionText.bottom
anchors.topMargin: 24
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: 16
height: avatarAppQRCodeImage.height
Image {
id: avatarAppQRCodeImage
source: resourceDirectoryUrl + "qml/hifi/simplifiedUI/avatarApp/images/qrCode.jpg"
anchors.top: parent.top
anchors.left: parent.left
width: 130
height: width
mipmap: true
fillMode: Image.PreserveAspectFit
}
HifiStylesUit.RalewayBold {
id: instructionText
anchors.top: avatarAppQRCodeImage.top
anchors.bottom: avatarAppQRCodeImage.bottom
anchors.left: avatarAppQRCodeImage.right
anchors.leftMargin: 30
anchors.right: parent.right
text: "Use your mobile phone to scan this QR code."
color: simplifiedUI.colors.text.black
size: 22
wrapMode: Text.Wrap
}
}
}
}
SimplifiedControls.VerticalScrollBar {
parent: textContainer
visible: parent.contentHeight > parent.height
size: parent.height / parent.contentHeight
}
}
HifiStylesUit.RalewayBold {
id: continueLink
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.leftMargin: 16
anchors.right: parent.right
anchors.rightMargin: 16
height: 96
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: "No thanks, I'll keep using my default avatar."
color: simplifiedUI.colors.text.lightBlue
opacity: continueMouseArea.containsMouse ? 1.0 : 0.7
size: 24
MouseArea {
id: continueMouseArea
hoverEnabled: true
anchors.fill: parent
onClicked: {
Tablet.playSound(TabletEnums.ButtonClick);
sendToScript({
"source": "SecondLaunchWindow.qml",
"method": "closeSecondLaunchWindow"
});
}
}
}
Image {
id: topLeftAccentImage
width: 130
height: 320
anchors.left: parent.left
anchors.top: parent.top
source: "images/standOutTopLeft.png"
}
Image {
id: bottomRightAccentImage
width: 250
height: 80
anchors.right: parent.right
anchors.bottom: parent.bottom
source: "images/standOutBottomRight.png"
}
signal sendToScript(var message);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

View file

@ -14,7 +14,6 @@
// START CONFIG OPTIONS
var DOCKED_QML_SUPPORTED = true;
var TOOLBAR_NAME = "com.highfidelity.interface.toolbar.system";
var DEFAULT_SCRIPTS_PATH_PREFIX = ScriptDiscoveryService.defaultScriptsPath + "/";
// END CONFIG OPTIONS
@ -352,6 +351,124 @@ function setOutputMuted(outputMuted) {
}
}
var TOP_BAR_HEIGHT_PX = 48;
var INITIAL_LAUNCH_QML_PATH = Script.resolvePath("./simplifiedFTUE/InitialLaunchWindow.qml");
var INITIAL_LAUNCH_WINDOW_TITLE = "Initial Launch";
var INITIAL_LAUNCH_PRESENTATION_MODE = Desktop.PresentationMode.NATIVE;
var INITIAL_WINDOW_FLAGS = 0x00000001 | // Qt::Window
0x00000008 | // Qt::Popup
0x00000002 | // Qt::Tool
0x00000800 | // Qt::FramelessWindowHint
0x40000000; // Qt::NoDropShadowWindowHint
var initialLaunchWindow = false;
function displayInitialLaunchWindow() {
if (initialLaunchWindow) {
return;
}
simplifiedEmote.handleFTUEScreensVisibilityChanged(true);
initialLaunchWindow = Desktop.createWindow(INITIAL_LAUNCH_QML_PATH, {
title: INITIAL_LAUNCH_WINDOW_TITLE,
presentationMode: INITIAL_LAUNCH_PRESENTATION_MODE,
isFullScreenWindow: true,
overrideFlags: INITIAL_WINDOW_FLAGS
});
initialLaunchWindow.fromQml.connect(onMessageFromInitialLaunchWindow);
Window.location = "file:///~/serverless/tutorial.json";
}
var SECOND_LAUNCH_QML_PATH = Script.resolvePath("simplifiedFTUE/SecondLaunchWindow.qml");
var SECOND_LAUNCH_WINDOW_TITLE = "Second Launch";
var SECOND_LAUNCH_PRESENTATION_MODE = Desktop.PresentationMode.NATIVE;
var SECOND_WINDOW_FLAGS = 0x00000001 | // Qt::Window
0x00000008 | // Qt::Popup
0x00000002 | // Qt::Tool
0x00000800 | // Qt::FramelessWindowHint
0x40000000; // Qt::NoDropShadowWindowHint
var secondLaunchWindow = false;
function displaySecondLaunchWindow() {
if (secondLaunchWindow) {
return;
}
simplifiedEmote.handleFTUEScreensVisibilityChanged(true);
secondLaunchWindow = Desktop.createWindow(SECOND_LAUNCH_QML_PATH, {
title: SECOND_LAUNCH_WINDOW_TITLE,
presentationMode: SECOND_LAUNCH_PRESENTATION_MODE,
isFullScreenWindow: true,
overrideFlags: SECOND_WINDOW_FLAGS
});
secondLaunchWindow.fromQml.connect(onMessageFromSecondLaunchWindow);
Window.location = "file:///~/serverless/tutorial.json";
}
function closeInitialLaunchWindow() {
if (initialLaunchWindow) {
initialLaunchWindow.fromQml.disconnect(onMessageFromInitialLaunchWindow);
initialLaunchWindow.close();
initialLaunchWindow = null;
}
simplifiedEmote.handleFTUEScreensVisibilityChanged(false);
}
function closeSecondLaunchWindow() {
if (secondLaunchWindow) {
secondLaunchWindow.fromQml.disconnect(onMessageFromSecondLaunchWindow);
secondLaunchWindow.close();
secondLaunchWindow = null;
}
simplifiedEmote.handleFTUEScreensVisibilityChanged(false);
}
var INITIAL_LAUNCH_WINDOW_MESSAGE_SOURCE = "InitialLaunchWindow.qml";
function onMessageFromInitialLaunchWindow(message) {
if (message.source !== INITIAL_LAUNCH_WINDOW_MESSAGE_SOURCE) {
return;
}
switch (message.method) {
case "closeInitialLaunchWindow":
closeInitialLaunchWindow();
var homeLocation = LocationBookmarks.getAddress("hqhome");
if (homeLocation) {
Window.location = homeLocation;
}
break;
default:
console.log("Unrecognized message from " + INITIAL_LAUNCH_WINDOW_MESSAGE_SOURCE + ": " + JSON.stringify(message));
break;
}
}
var SECOND_LAUNCH_WINDOW_MESSAGE_SOURCE = "SecondLaunchWindow.qml";
function onMessageFromSecondLaunchWindow(message) {
if (message.source !== SECOND_LAUNCH_WINDOW_MESSAGE_SOURCE) {
return;
}
switch (message.method) {
case "closeSecondLaunchWindow":
closeSecondLaunchWindow();
var homeLocation = LocationBookmarks.getAddress("hqhome");
if (homeLocation) {
Window.location = homeLocation;
}
break;
default:
console.log("Unrecognized message from " + SECOND_LAUNCH_WINDOW_MESSAGE_SOURCE + ": " + JSON.stringify(message));
break;
}
}
var WAIT_FOR_TOP_BAR_MS = 1000;
function sendLocalStatusToQml() {
@ -397,6 +514,14 @@ function onMessageFromTopBar(message) {
si.toggleStatus();
break;
case "displayInitialLaunchWindow":
displayInitialLaunchWindow();
break;
case "displaySecondLaunchWindow":
displaySecondLaunchWindow();
break;
default:
console.log("Unrecognized message from " + TOP_BAR_MESSAGE_SOURCE + ": " + JSON.stringify(message));
break;
@ -425,7 +550,6 @@ var TOP_BAR_QML_PATH = Script.resourcesPath() + "qml/hifi/simplifiedUI/topBar/Si
var TOP_BAR_WINDOW_TITLE = "Simplified Top Bar";
var TOP_BAR_PRESENTATION_MODE = Desktop.PresentationMode.NATIVE;
var TOP_BAR_WIDTH_PX = Window.innerWidth;
var TOP_BAR_HEIGHT_PX = 48;
var topBarWindow = false;
function loadSimplifiedTopBar() {
var windowProps = {
@ -436,16 +560,9 @@ function loadSimplifiedTopBar() {
y: TOP_BAR_HEIGHT_PX
}
};
if (DOCKED_QML_SUPPORTED) {
windowProps.presentationWindowInfo = {
dockArea: Desktop.DockArea.TOP
};
} else {
windowProps.position = {
x: Window.x,
y: Window.y
};
}
windowProps.presentationWindowInfo = {
dockArea: Desktop.DockArea.TOP
};
topBarWindow = Desktop.createWindow(TOP_BAR_QML_PATH, windowProps);
topBarWindow.fromQml.connect(onMessageFromTopBar);
@ -510,21 +627,38 @@ function onHMDInputDeviceMutedChanged(isMuted) {
function onGeometryChanged(rect) {
updateInputDeviceMutedOverlay(Audio.muted);
updateOutputDeviceMutedOverlay(isOutputMuted());
if (topBarWindow && !DOCKED_QML_SUPPORTED) {
topBarWindow.size = {
"x": rect.width,
"y": TOP_BAR_HEIGHT_PX
};
topBarWindow.position = {
"x": rect.x,
"y": rect.y
};
}
var initialLaunchWindowIsMinimized = false;
var secondLaunchWindowIsMinimized = false;
function onWindowMinimizedChanged(isMinimized) {
if (isMinimized) {
handleInitialLaunchWindowVisibleChanged(false);
handleSecondLaunchWindowVisibleChanged(false);
} else if (!HMD.active) {
handleInitialLaunchWindowVisibleChanged(true);
handleSecondLaunchWindowVisibleChanged(true);
}
}
function onWindowMinimizedChanged() {
// prerequisite placeholder for Reduce Friction of Customer Acquisition sub task: https://highfidelity.atlassian.net/browse/DEV-585
print("WINDOW MINIMIZED CHANGED SIGNAL");
function handleInitialLaunchWindowVisibleChanged(shouldBeVisible) {
if (shouldBeVisible && !initialLaunchWindow && initialLaunchWindowIsMinimized) {
displayInitialLaunchWindow();
initialLaunchWindowIsMinimized = false;
} else if (!shouldBeVisible && initialLaunchWindow) {
closeInitialLaunchWindow();
initialLaunchWindowIsMinimized = true;
}
}
function handleSecondLaunchWindowVisibleChanged(shouldBeVisible) {
if (shouldBeVisible && !secondLaunchWindow && secondLaunchWindowIsMinimized) {
displaySecondLaunchWindow();
secondLaunchWindowIsMinimized = false;
} else if (!shouldBeVisible && secondLaunchWindow) {
closeSecondLaunchWindow();
secondLaunchWindowIsMinimized = true;
}
}
function onDisplayModeChanged(isHMDMode) {
@ -534,8 +668,12 @@ function onDisplayModeChanged(isHMDMode) {
if (isHMDMode) {
onHMDInputDeviceMutedChanged(Audio.mutedHMD);
handleInitialLaunchWindowVisibleChanged(false);
handleSecondLaunchWindowVisibleChanged(false);
} else {
onDesktopInputDeviceMutedChanged(Audio.mutedDesktop);
handleInitialLaunchWindowVisibleChanged(true);
handleSecondLaunchWindowVisibleChanged(true);
}
}
@ -578,9 +716,9 @@ function restoreLODSettings() {
}
var nametag = Script.require("./simplifiedNametag/simplifiedNametag.js?" + Date.now());
var si = Script.require("./simplifiedStatusIndicator/simplifiedStatusIndicator.js?" + Date.now());
var emote = Script.require("../simplifiedEmote/simplifiedEmote.js?" + Date.now());
var nametag = Script.require("./simplifiedNametag/simplifiedNametag.js");
var si = Script.require("./simplifiedStatusIndicator/simplifiedStatusIndicator.js");
var simplifiedEmote = Script.require("../simplifiedEmote/simplifiedEmote.js");
var oldShowAudioTools;
var oldShowBubbleTools;
var keepExistingUIAndScriptsSetting = Settings.getValue("simplifiedUI/keepExistingUIAndScripts", false);
@ -647,6 +785,14 @@ function shutdown() {
settingsAppWindow.close();
}
if (initialLaunchWindow) {
closeInitialLaunchWindow();
}
if (secondLaunchWindow) {
closeSecondLaunchWindow();
}
maybeDeleteInputDeviceMutedOverlay();
maybeDeleteOutputDeviceMutedOverlay();