Working on initial/second launch

This commit is contained in:
RebeccaStankus 2019-09-27 09:15:39 -07:00
parent b491d00c00
commit f4ecd3dcd8
20 changed files with 614 additions and 9 deletions

View file

@ -55,7 +55,7 @@ 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;
MyAvatar.useFullAvatarURL(topBarInventoryModel.get(0).download_url);
}
}
}
@ -113,12 +113,68 @@ Rectangle {
topBarInventoryModel.getNextPage();
} else {
inventoryFullyReceived = true;
var scriptExecutionCount = Settings.getValue("simplifiedUI/SUIScriptExecutionCount");
var currentAvatarURL = MyAvatar.skeletonModelURL;
var userIsWearingDefaultAvatar = currentAvatarURL.indexOf("DefaultAvatar") > -1;
var currentAvatarIsValid = MyAvatar.skeletonModelURL.indexOf("fst") === -1;
var avatarHasBeenAutoSelectedBefore = Settings.getValue("simplifiedUI/alreadyAutoSelectedAvatar", false);
var userHasValidAvatarInInventory = topBarInventoryModel.count > 0 &&
topBarInventoryModel.get(0).download_url.indexOf(".fst") > -1 &&
topBarInventoryModel.get(0).download_url.indexOf("mannequin.fst") === -1;
var userHasOldDefaultAvatar = MyAvatar.skeletonModelURL.indexOf("mannequin.fst") === -1;
var defaultAvatarURLPrefixPart1 = "http://hifi-content.s3-us-west-1.amazonaws.com/Experiences/Releases/simplifiedUI/simplifiedFTUE/avatarModels/DefaultAvatar_";
var defaultAvatarURLPrefixPart2 = "/avatar.fst";
var defaultAvatarColors = ["Blue", "Cyan", "Green", "Pink", "Red", "Yellow"];
var avatarColor;
// 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) {
// FOR TESTING__________REMOVE
userHasValidAvatarInInventory = false;
// 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 (!currentAvatarIsValid || userHasOldDefaultAvatar || (!avatarHasBeenAutoSelectedBefore && userIsWearingDefaultAvatar)) {
if (userHasValidAvatarInInventory) {
MyAvatar.useFullAvatarURL(topBarInventoryModel.get(0).download_url);
userIsWearingDefaultAvatar = false;
} else {
if (!userIsWearingDefaultAvatar) { // assign a random color default avatar
avatarColor = defaultAvatarColors[Math.floor(Math.random() * defaultAvatarColors.length)];
var avatarModelURL = defaultAvatarURLPrefixPart1 + avatarColor + defaultAvatarURLPrefixPart2;
MyAvatar.useFullAvatarURL(avatarModelURL);
userIsWearingDefaultAvatar = true;
}
}
}
// If the user is not wearing a default avatar at this point, we do not need to check inventory again. This check ensures the setting is changed if the
// user came in on their first run using a valid non-wolf avatar (in this case we will never auto-select) or if we selected the top inventory item for them.
if (!userIsWearingDefaultAvatar) {
Settings.setValue("simplifiedUI/alreadyAutoSelectedAvatar", true);
MyAvatar.skeletonModelURL = topBarInventoryModel.get(0).download_url;
avatarHasBeenAutoSelectedBefore = true;
}
if (scriptExecutionCount === 1) {
if (userIsWearingDefaultAvatar) {
if (!avatarColor) { // get the color of the default avatar they are using
var indexOfDefaultAvatarColor = 123;
var numberCharsAfterDefaultColorName = 11;
avatarColor = currentAvatarURL.substring(indexOfDefaultAvatarColor , MyAvatar.skeletonModelURL.length - numberCharsAfterDefaultColorName)
}
// There could be a race condition here. We are changing the setting and then calling simplifiedUI.js to check that setting shortly after.
// We can send the page we want to display instead of reading the setting to avoid this.
sendToScript({
"source": "SimplifiedTopBar.qml",
"method": "displayInitialLaunchWindow",
"data": {
"avatarColor": avatarColor
}
});
}
} else if (scriptExecutionCount === 2 && userIsWearingDefaultAvatar) {
sendToScript({
"source": "SimplifiedTopBar.qml",
"method": "displaySecondLaunchWindow"
});
}
}
}
@ -150,7 +206,6 @@ Rectangle {
}
}
Item {
id: avatarButtonContainer
anchors.verticalCenter: parent.verticalCenter

View file

@ -0,0 +1,260 @@
//
// 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
Component.onCompleted: {
if (Settings.getValue("simplifiedUI/alreadyAutoSelectedAvatar", false)) {
tempAvatarPageContainer.visible = false;
controlsContainer.visible = true;
}
}
Image {
id: topLeftAccentImage
width: 60
height: 150
anchors.left: parent.left
anchors.top: parent.top
source: "images/defaultTopLeft.png"
}
Image {
id: bottomRightAccentImage
width: 30
height: 100
anchors.right: parent.right
anchors.bottom: parent.bottom
source: "images/defaultBottomRight.png"
}
Item {
id: tempAvatarPageContainer
visible: true
GridLayout {
id: tempAvatarPageGrid
anchors.fill: parent
flow: root.width < root.height ? GridLayout.LeftToRight : GridLayout.TopToBottom
Item {
id: textAndQRContainer
HifiStylesUit.GraphikSemiBold {
id: headerText
width: 700
height: 120
text: "We know this isn't you..."
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: simplifiedUI.colors.text.darkGrey
size: 36
}
HifiStylesUit.GraphikSemiBold {
width: 700
height: 500
text: "But, we've given you this <b>temporary avatar</b> to use<br></br>
for today. If you see this avatar in-world, walk up and<br></br>
say hello to other new users!<br></br><br></br>
<b>We want you to be you</b> so we've built an Avatar Creator<br></br>
App that's as easy as taking a selfie and picking your<br></br>
outfits! Available now on iOS and Android Platforms."
anchors.top: headerText.bottom
horizontalAlignment: Text.AlignHLeft
verticalAlignment: Text.AlignVCenter
color: simplifiedUI.colors.text.darkGrey
size: 24
}
Item {
id: qrAndInstructionsContainer
Image {
id: avatarAppQRCodeImage
width: 200
height: 200
anchors.right: parent.right
anchors.bottom: parent.bottom
source: "images/qrCode.png"
}
HifiStylesUit.GraphikSemiBold {
width: 600
height: 80
text: "Use your mobile phone to scan this QR code."
anchors.left: avatarAppQRCodeImage.right
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: simplifiedUI.colors.text.darkGrey
size: 24
}
}
HifiStylesUit.GraphikSemiBold {
width: 250
height: 120
text: "Continue"
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: simplifiedUI.colors.text.lightBlue
opacity: continueMouseArea.containsMouse ? 1.0 : 0.8
size: 30
MouseArea {
id: continueMouseArea
hoverEnabled: false
anchors.fill: parent
onClicked: {
Tablet.playSound(TabletEnums.ButtonClick);
Print("CONTINUE CLICKED");
tempAvatarPageContainer.visible = false;
controlsContainer.visible = true;
}
}
}
}
Item {
id: tempAvatarImageContainer
Image {
id: tempAvatarImage
width: tempAvatarPageGrid.flow === GridLayout.LeftToRight ? 250 : 500
height: tempAvatarPageGrid.flow === GridLayout.LeftToRight ? 500 : 1000
source: "images/DefaultAvatar_" + MyAvatar.skeletonModelURL.substring(123, MyAvatar.skeletonModelURL.length - 11) + ".png"
}
}
}
}
Item {
id: controlsContainer
visible: false
HifiStylesUit.GraphikSemiBold {
text: "These are your avatar controls to<br></br>
<b>Interact with and move around in your new HQ.</b>"
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: simplifiedUI.colors.text.darkGrey
size: 34
}
GridLayout {
Item {
id: controlsImagesContainer
Item {
Image {
id: walkingControls
width: 500
height: 350
source: "images/walkingControls.png"
}
}
Item {
Image {
id: mouseControls
width: 600
height: 350
source: "images/mouseControls.png"
}
}
Item {
Image {
id: runJumpControls
width: 300
height: 250
source: "images/runJumpControls.png"
}
}
Item {
Image {
id: cameraControls
width: 500
height: 50
source: "images/cameraControls.png"
}
}
}
}
HifiStylesUit.GraphikSemiBold {
text: "Learn more about our controls."
anchors.bottom: parent.bottom
anchors.left: parent.left
width: 200
height: 50
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: simplifiedUI.colors.text.lightBlue
opacity: learnMoreAboutControlsMouseArea.containsMouse ? 1.0 : 0.8
size: 12
MouseArea {
id: learnMoreAboutControlsMouseArea
hoverEnabled: false
anchors.fill: parent
onClicked: {
Tablet.playSound(TabletEnums.ButtonClick);
// TODO open docs in browser
Print("LEARN MORE ABOUT CONTROLS CLICKED");
}
}
}
HifiStylesUit.GraphikSemiBold {
text: "I've got a good grip on the controls."
anchors.bottom: parent.bottom
width: 700
height: 120
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: simplifiedUI.colors.text.lightBlue
opacity: goodGripMouseArea.containsMouse ? 1.0 : 0.8
size: 30
MouseArea {
id: goodGripMouseArea
hoverEnabled: false
anchors.fill: parent
onClicked: {
Tablet.playSound(TabletEnums.ButtonClick);
Print("GOOD GRIP CLICKED");
sendToScript({
"source": "InitialLaunchWindow.qml",
"method": "closeInitialLaunchWindow"
});
}
}
}
}
signal sendToScript(var message);
}

View file

@ -0,0 +1,138 @@
//
// 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
Image {
id: topLeftAccentImage
width: 60
height: 150
anchors.left: parent.left
anchors.top: parent.top
source: "images/standOutTopLeft.png"
}
Image {
id: bottomRightAccentImage
width: 30
height: 100
anchors.right: parent.right
anchors.bottom: parent.bottom
source: "images/standOutBottomRight.png"
}
Item {
GridLayout {
id: controlsPageGrid
anchors.fill: parent
flow: root.width < root.height ? GridLayout.LeftToRight : GridLayout.TopToBottom
Item {
id: textAndQRContainer
HifiStylesUit.GraphikSemiBold {
id: headerText
width: 700
height: 120
text: "Stand out from the crowd!"
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: simplifiedUI.colors.text.darkGrey
size: 36
}
HifiStylesUit.GraphikSemiBold {
width: 700
height: 250
text: "You can create and upload custom avatars from our<br></br>
Avatar Creator App. It's as easy as taking a selfie.<br></br>
Available now on iOS and Android Platforms."
anchors.top: headerText.bottom
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: simplifiedUI.colors.text.darkGrey
size: 24
}
Item {
id: qrAndInstructionsContainer
Image {
id: avatarAppQRCodeImage
width: 200
height: 200
source: "images/qrCode.png"
}
HifiStylesUit.GraphikSemiBold {
width: 600
height: 80
text: "Use your mobile phone to scan this QR code."
anchors.top: avatarAppQRCodeImage.bottom
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: simplifiedUI.colors.text.darkGrey
size: 24
}
}
HifiStylesUit.GraphikSemiBold {
text: "No thanks, I'll keep using my default avatar."
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: simplifiedUI.colors.text.lightBlue
opacity: noThanksMouseArea.containsMouse ? 1.0 : 0.8
size: 12
MouseArea {
id: noThanksMouseArea
hoverEnabled: false
anchors.fill: parent
onClicked: {
Tablet.playSound(TabletEnums.ButtonClick);
Print("NO THANKS CLICKED");
sendToScript({
"source": "SecondLaunchWindow.qml",
"method": "closeInitialLaunchWindow"
});
}
}
}
}
}
Item {
id: heroImageContainer
Image {
id: heroImage
width: 600
height: 350
source: "images/hero.png"
}
}
}
signal sendToScript(var message);
}

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

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: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 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

@ -358,6 +358,132 @@ function setOutputMuted(outputMuted) {
}
}
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_LAUNCH_WIDTH_PX = Window.innerWidth;
var INITIAL_LAUNCH_HEIGHT_PX = Window.innerHeight + TOP_BAR_HEIGHT_PX;
var INITIAL_WINDOW_FLAGS = 0x00000001 | // Qt::Window
0x00000008 | // Qt::Popup
0x00000800 | // Qt::FramelessWindowHint
0x40000000; // Qt::NoDropShadowWindowHint
var initialLaunchWindow = false;
function displayInitialLaunchWindow() {
print("DISPLAY INITIAL LAUNCH WINDOW.");
if (initialLaunchWindow) {
initialLaunchWindow.close();
// This really shouldn't be necessary.
// This signal really should automatically be called by the signal handler set up below.
// But fixing that requires an engine change, so this workaround will do.
return;
}
initialLaunchWindow = Desktop.createWindow(INITIAL_LAUNCH_QML_PATH, {
title: INITIAL_LAUNCH_WINDOW_TITLE,
presentationMode: INITIAL_LAUNCH_PRESENTATION_MODE,
size: {
x: INITIAL_LAUNCH_WIDTH_PX,
y: INITIAL_LAUNCH_HEIGHT_PX
},
position: {
x: Window.x,
y: Window.y
},
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_LAUNCH_WIDTH_PX = Window.innerWidth;
var SECOND_LAUNCH_HEIGHT_PX = Window.innerHeight + TOP_BAR_HEIGHT_PX;
var SECOND_WINDOW_FLAGS = 0x00000001 | // Qt::Window
0x00000008 | // Qt::Popup
0x00000800 | // Qt::FramelessWindowHint
0x40000000; // Qt::NoDropShadowWindowHint
var secondLaunchWindow = false;
function displaySecondLaunchWindow() {
print("DISPLAY SECOND LAUNCH WINDOW.");
if (secondLaunchWindow) {
secondLaunchWindow.close();
// This really shouldn't be necessary.
// This signal really should automatically be called by the signal handler set up below.
// But fixing that requires an engine change, so this workaround will do.
return;
}
secondLaunchWindow = Desktop.createWindow(INITIAL_LAUNCH_QML_PATH, {
title: SECOND_LAUNCH_WINDOW_TITLE,
presentationMode: SECOND_LAUNCH_PRESENTATION_MODE,
size: {
x: SECOND_LAUNCH_WIDTH_PX,
y: SECOND_LAUNCH_HEIGHT_PX
},
position: {
x: Window.x,
y: Window.y
},
overrideFlags: SECOND_WINDOW_FLAGS
});
secondLaunchWindow.fromQml.connect(onMessageFromSecondLaunchWindow);
Window.location = "file:///~serverless/tutorial.json";
}
function closeInitialLaunchWindow() {
initialLaunchWindow.fromQml.disconnect(onMessageFromInitialLaunchWindow);
// TODO make this go to bookmark
// Window.location = "hqhome";
initialLaunchWindow.close();
}
function closeSecondLaunchWindow() {
secondLaunchWindow.fromQml.disconnect(onMessageFromSecondLaunchWindow);
// TODO make this go to bookmark
// Window.location = "hqhome";
secondLaunchWindow.close();
}
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();
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();
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() {
@ -403,6 +529,15 @@ function onMessageFromTopBar(message) {
si.toggleStatus();
break;
case "displayInitialLaunchWindow":
displayInitialLaunchWindow();
break;
case "displaySecondLaunchWindow":
displaySecondLaunchWindow();
print("DISPLAY SECOND LAUNCH WINDOW");
break;
default:
console.log("Unrecognized message from " + TOP_BAR_MESSAGE_SOURCE + ": " + JSON.stringify(message));
break;
@ -530,11 +665,24 @@ function onGeometryChanged(rect) {
"y": rect.y
};
}
if (initialLaunchWindow) {
initialLaunchWindow.size = {
"x": rect.width,
"y": rect.height
};
initialLaunchWindow.position = {
"x": rect.x,
"y": rect.y
};
}
}
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 onWindowMinimizedChanged(isMinimized) {
if (isMinimized) {
initialLaunchWindow.setVisible(false);
} else {
initialLaunchWindow.show();
}
}
function onDisplayModeChanged(isHMDMode) {
@ -657,6 +805,10 @@ function shutdown() {
settingsAppWindow.close();
}
if (initialLaunchWindow) {
closeInitialLaunchWindow();
}
maybeDeleteInputDeviceMutedOverlay();
maybeDeleteOutputDeviceMutedOverlay();