diff --git a/interface/resources/images/backward.svg b/interface/resources/images/backward.svg
index e4502fa80e..a913ad9cd0 100644
--- a/interface/resources/images/backward.svg
+++ b/interface/resources/images/backward.svg
@@ -1,6 +1,6 @@
-
diff --git a/interface/resources/images/forward.svg b/interface/resources/images/forward.svg
index 0c5cbe3d0c..dde9322b9e 100644
--- a/interface/resources/images/forward.svg
+++ b/interface/resources/images/forward.svg
@@ -1,6 +1,6 @@
-
diff --git a/interface/resources/qml/controls/TabletWebButton.qml b/interface/resources/qml/controls/TabletWebButton.qml
new file mode 100644
index 0000000000..a5876d08dd
--- /dev/null
+++ b/interface/resources/qml/controls/TabletWebButton.qml
@@ -0,0 +1,53 @@
+//
+// TabletWebButton.qml
+//
+// Created by Dante Ruiz on 2017/4/13
+// Copyright 2015 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+import Hifi 1.0
+import QtQuick 2.4
+import "../styles-uit"
+
+Rectangle {
+ property alias text: label.text
+ property alias pixelSize: label.font.pixelSize;
+ property bool selected: false
+ property bool hovered: false
+ property bool enabled: false
+ property int spacing: 2
+ property var action: function () {}
+ property string enabledColor: hifi.colors.blueHighlight
+ property string disabledColor: hifi.colors.blueHighlight
+ property string highlightColor: hifi.colors.blueHighlight;
+ width: label.width + 64
+ height: 32
+ color: hifi.colors.white
+ HifiConstants { id: hifi }
+ RalewaySemiBold {
+ id: label;
+ color: enabledColor
+ font.pixelSize: 15;
+ anchors {
+ horizontalCenter: parent.horizontalCenter;
+ verticalCenter: parent.verticalCenter;
+ }
+ }
+
+
+ Rectangle {
+ id: indicator
+ width: parent.width
+ height: selected ? 3 : 1
+ anchors {
+ left: parent.left
+ right: parent.right
+ bottom: parent.bottom
+ }
+ color: hifi.colors.blueHighlight
+ visible: parent.selected || hovered
+ }
+}
diff --git a/interface/resources/qml/controls/TabletWebView.qml b/interface/resources/qml/controls/TabletWebView.qml
index 93e693ab2f..9a08e8b866 100644
--- a/interface/resources/qml/controls/TabletWebView.qml
+++ b/interface/resources/qml/controls/TabletWebView.qml
@@ -2,97 +2,81 @@ import QtQuick 2.5
import QtQuick.Controls 1.4
import QtWebEngine 1.2
import QtWebChannel 1.0
+import HFTabletWebEngineProfile 1.0
import "../controls-uit" as HiFiControls
import "../styles" as HifiStyles
import "../styles-uit"
-import HFWebEngineProfile 1.0
-import HFTabletWebEngineProfile 1.0
import "../"
+import "."
Item {
id: web
+ HifiConstants { id: hifi }
width: parent.width
height: parent.height
property var parentStackItem: null
- property int headerHeight: 38
+ property int headerHeight: 70
property string url
- property string address: url //for compatibility
+ property alias address: displayUrl.text //for compatibility
property string scriptURL
property alias eventBridge: eventBridgeWrapper.eventBridge
property bool keyboardEnabled: HMD.active
property bool keyboardRaised: false
property bool punctuationMode: false
property bool isDesktop: false
- property WebEngineView view: loader.currentView
property int currentPage: -1 // used as a model for repeater
property alias pagesModel: pagesModel
- Row {
+ Rectangle {
id: buttons
- HifiConstants { id: hifi }
- HifiStyles.HifiConstants { id: hifistyles }
- height: headerHeight
- spacing: 4
- anchors.top: parent.top
- anchors.topMargin: 8
- anchors.left: parent.left
- anchors.leftMargin: 8
- HiFiGlyphs {
- id: back;
- enabled: currentPage >= 0
- text: hifi.glyphs.backward
- color: enabled ? hifistyles.colors.text : hifistyles.colors.disabledText
- size: 48
- MouseArea { anchors.fill: parent; onClicked: goBack() }
- }
-
- HiFiGlyphs {
- id: forward;
- enabled: currentPage < pagesModel.count - 1
- text: hifi.glyphs.forward
- color: enabled ? hifistyles.colors.text : hifistyles.colors.disabledText
- size: 48
- MouseArea { anchors.fill: parent; onClicked: goForward() }
- }
-
- HiFiGlyphs {
- id: reload;
- enabled: view != null;
- text: (view !== null && view.loading) ? hifi.glyphs.close : hifi.glyphs.reload
- color: enabled ? hifistyles.colors.text : hifistyles.colors.disabledText
- size: 48
- MouseArea { anchors.fill: parent; onClicked: reloadPage(); }
- }
-
- }
+ width: parent.width
+ height: parent.headerHeight
+ color: hifi.colors.white
- TextField {
- id: addressBar
- height: 30
- anchors.right: parent.right
- anchors.rightMargin: 8
- anchors.left: buttons.right
- anchors.leftMargin: 0
- anchors.verticalCenter: buttons.verticalCenter
- focus: true
- text: address
- Component.onCompleted: ScriptDiscoveryService.scriptsModelFilter.filterRegExp = new RegExp("^.*$", "i")
+ Row {
+ id: nav
+ anchors {
+ top: parent.top
+ topMargin: 10
+ horizontalCenter: parent.horizontalCenter
+ }
+ spacing: 120
+
+ TabletWebButton {
+ id: back
+ enabledColor: hifi.colors.baseGray
+ enabled: false
+ text: "BACK"
- Keys.onPressed: {
- switch (event.key) {
- case Qt.Key_Enter:
- case Qt.Key_Return:
- event.accepted = true;
- if (text.indexOf("http") != 0) {
- text = "http://" + text;
- }
- //root.hidePermissionsBar();
- web.keyboardRaised = false;
- gotoPage(text);
- break;
+ MouseArea {
+ anchors.fill: parent
+ onClicked: goBack()
+ hoverEnabled: true
+
+ }
+ }
-
+ TabletWebButton {
+ id: close
+ enabledColor: hifi.colors.darkGray
+ text: "CLOSE"
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: closeWebEngine()
+ }
+ }
+ }
+
+
+ RalewaySemiBold {
+ id: displayUrl
+ color: hifi.colors.baseGray
+ font.pixelSize: 12
+ anchors {
+ top: nav.bottom
+ horizontalCenter: parent.horizontalCenter;
}
}
}
@@ -100,15 +84,30 @@ Item {
ListModel {
id: pagesModel
onCountChanged: {
- currentPage = count - 1
+ currentPage = count - 1;
+ if (currentPage > 0) {
+ back.enabledColor = hifi.colors.darkGray;
+ } else {
+ back.enabledColor = hifi.colors.baseGray;
+ }
}
}
function goBack() {
- if (currentPage > 0) {
- currentPage--;
- } else if (parentStackItem) {
+ if (webview.canGoBack) {
+ pagesModel.remove(currentPage);
+ webview.goBack();
+ } else if (currentPage > 0) {
+ pagesModel.remove(currentPage);
+ }
+ }
+
+
+ function closeWebEngine() {
+ if (parentStackItem) {
parentStackItem.pop();
+ } else {
+ web.visible = false;
}
}
@@ -130,18 +129,20 @@ Item {
function urlAppend(url) {
var lurl = decodeURIComponent(url)
- if (lurl[lurl.length - 1] !== "/")
+ if (lurl[lurl.length - 1] !== "/") {
lurl = lurl + "/"
- if (currentPage === -1 || pagesModel.get(currentPage).webUrl !== lurl) {
- pagesModel.append({webUrl: lurl})
+ }
+ if (currentPage === -1 || (pagesModel.get(currentPage).webUrl !== lurl && !timer.running)) {
+ timer.start();
+ pagesModel.append({webUrl: lurl});
}
}
onCurrentPageChanged: {
- if (currentPage >= 0 && currentPage < pagesModel.count && loader.item !== null) {
- loader.item.url = pagesModel.get(currentPage).webUrl
- web.url = loader.item.url
- web.address = loader.item.url
+ if (currentPage >= 0 && currentPage < pagesModel.count) {
+ webview.url = pagesModel.get(currentPage).webUrl;
+ web.url = webview.url;
+ web.address = webview.url;
}
}
@@ -155,45 +156,110 @@ Item {
property var eventBridge;
}
- Loader {
- id: loader
+ Timer {
+ id: timer
+ interval: 100
+ running: false
+ repeat: false
+ onTriggered: timer.stop();
+ }
- property WebEngineView currentView: null
+
+
+ WebEngineView {
+ id: webview
+ objectName: "webEngineView"
+ x: 0
+ y: 0
width: parent.width
- height: parent.height - web.headerHeight
- asynchronous: true
+ height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height - web.headerHeight : parent.height - web.headerHeight
anchors.top: buttons.bottom
- active: false
- source: "../TabletBrowser.qml"
- onStatusChanged: {
- if (loader.status === Loader.Ready) {
- currentView = item.webView
- item.webView.userScriptUrl = web.scriptURL
- if (currentPage >= 0) {
- //we got something to load already
- item.url = pagesModel.get(currentPage).webUrl
- web.address = loader.item.url
+ profile: HFTabletWebEngineProfile {
+ id: webviewTabletProfile
+ storageName: "qmlTabletWebEngine"
+ }
+
+ property string userScriptUrl: ""
+
+ // creates a global EventBridge object.
+ WebEngineScript {
+ id: createGlobalEventBridge
+ sourceCode: eventBridgeJavaScriptToInject
+ injectionPoint: WebEngineScript.DocumentCreation
+ worldId: WebEngineScript.MainWorld
+ }
+
+ // detects when to raise and lower virtual keyboard
+ WebEngineScript {
+ id: raiseAndLowerKeyboard
+ injectionPoint: WebEngineScript.Deferred
+ sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js"
+ worldId: WebEngineScript.MainWorld
+ }
+
+ // User script.
+ WebEngineScript {
+ id: userScript
+ sourceUrl: webview.userScriptUrl
+ injectionPoint: WebEngineScript.DocumentReady // DOM ready but page load may not be finished.
+ worldId: WebEngineScript.MainWorld
+ }
+
+ userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ]
+
+ property string newUrl: ""
+
+ webChannel.registeredObjects: [eventBridgeWrapper]
+
+ Component.onCompleted: {
+ // Ensure the JS from the web-engine makes it to our logging
+ webview.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
+ console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message);
+ });
+
+ webview.profile.httpUserAgent = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36";
+ web.address = url;
+ }
+
+ onFeaturePermissionRequested: {
+ grantFeaturePermission(securityOrigin, feature, true);
+ }
+
+ onLoadingChanged: {
+ keyboardRaised = false;
+ punctuationMode = false;
+ keyboard.resetShiftMode(false);
+
+ // Required to support clicking on "hifi://" links
+ if (WebEngineView.LoadStartedStatus == loadRequest.status) {
+ urlAppend(loadRequest.url.toString())
+ var url = loadRequest.url.toString();
+ if (urlHandler.canHandleUrl(url)) {
+ if (urlHandler.handleUrl(url)) {
+ root.stop();
+ }
}
}
}
- }
+ onNewViewRequested: {
+ request.openIn(webview);
+ }
+ }
+
Component.onCompleted: {
web.isDesktop = (typeof desktop !== "undefined");
address = url;
- loader.active = true
}
- Keys.onPressed: {
+ Keys.onPressed: {
switch(event.key) {
- case Qt.Key_L:
- if (event.modifiers == Qt.ControlModifier) {
- event.accepted = true
- addressBar.selectAll()
- addressBar.forceActiveFocus()
- }
- break;
+ case Qt.Key_L:
+ if (event.modifiers == Qt.ControlModifier) {
+ event.accepted = true
+ }
+ break;
}
}
}
diff --git a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml
index 356ff92664..bed1f82ac2 100644
--- a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml
+++ b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml
@@ -20,8 +20,10 @@ import "../toolbars"
import "../../styles-uit" as HifiStyles
import "../../controls-uit" as HifiControls
+// references HMD, AddressManager, AddressBarDialog from root context
+
StackView {
- id: root
+ id: root;
HifiConstants { id: hifi }
HifiStyles.HifiConstants { id: hifiStyleConstants }
initialItem: addressBarDialog
@@ -34,24 +36,16 @@ StackView {
property string metaverseBase: addressBarDialog.metaverseServerUrl + "/api/v1/";
property var tablet: null;
- property bool isDesktop: false;
- Component { id: tabletStoryCard; TabletStoryCard {} }
+ Component { id: tabletWebView; TabletWebView {} }
Component.onCompleted: {
- root.currentItem.focus = true;
- root.currentItem.forceActiveFocus();
- addressLine.focus = true;
- addressLine.forceActiveFocus();
fillDestinations();
updateLocationText(false);
+ fillDestinations();
+ addressLine.focus = !HMD.active;
root.parentChanged.connect(center);
center();
- isDesktop = (typeof desktop !== "undefined");
tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
-
- if (desktop) {
- root.title = "GOTO";
- }
}
Component.onDestruction: {
root.parentChanged.disconnect(center);
@@ -68,9 +62,9 @@ StackView {
}
function goCard(targetString) {
if (0 !== targetString.indexOf('hifi://')) {
- var card = tabletStoryCard.createObject();
- card.setUrl(addressBarDialog.metaverseServerUrl + targetString);
- card.eventBridge = root.eventBridge;
+ var card = tabletWebView.createObject();
+ card.url = addressBarDialog.metaverseServerUrl + targetString;
+ card.parentStackItem = root;
root.push(card);
return;
}
@@ -78,8 +72,6 @@ StackView {
toggleOrGo(true, targetString);
clearAddressLineTimer.start();
}
-
- property bool isCursorVisible: false // Override default cursor visibility.
AddressBarDialog {
@@ -102,16 +94,11 @@ StackView {
onMetaverseServerUrlChanged: updateLocationTextTimer.start();
Rectangle {
id: navBar
- width: 480
- height: 70
+ width: parent.width
+ height: 50;
color: hifiStyleConstants.colors.white
- anchors {
- top: parent.top
- right: parent.right
- rightMargin: 0
- left: parent.left
- leftMargin: 0
- }
+ anchors.top: parent.top;
+ anchors.left: parent.left;
ToolbarButton {
id: homeButton
@@ -129,8 +116,14 @@ StackView {
}
ToolbarButton {
id: backArrow;
+ buttonState: addressBarDialog.backEnabled;
imageURL: "../../../images/backward.svg";
- onClicked: addressBarDialog.loadBack();
+ buttonEnabled: addressBarDialog.backEnabled;
+ onClicked: {
+ if (buttonEnabled) {
+ addressBarDialog.loadBack();
+ }
+ }
anchors {
left: homeButton.right
verticalCenter: parent.verticalCenter
@@ -138,8 +131,14 @@ StackView {
}
ToolbarButton {
id: forwardArrow;
+ buttonState: addressBarDialog.forwardEnabled;
imageURL: "../../../images/forward.svg";
- onClicked: addressBarDialog.loadForward();
+ buttonEnabled: addressBarDialog.forwardEnabled;
+ onClicked: {
+ if (buttonEnabled) {
+ addressBarDialog.loadForward();
+ }
+ }
anchors {
left: backArrow.right
verticalCenter: parent.verticalCenter
@@ -149,85 +148,80 @@ StackView {
Rectangle {
id: addressBar
- width: 480
+ width: parent.width
height: 70
color: hifiStyleConstants.colors.white
anchors {
- top: navBar.bottom
- right: parent.right
- rightMargin: 16
- left: parent.left
- leftMargin: 16
+ top: navBar.bottom;
+ left: parent.left;
}
- property int inputAreaHeight: 70
- property int inputAreaStep: (height - inputAreaHeight) / 2
-
HifiStyles.RalewayLight {
id: notice;
- font.pixelSize: hifi.fonts.pixelSize * 0.50;
+ font.pixelSize: hifi.fonts.pixelSize * 0.7;
anchors {
- top: parent.top
- topMargin: parent.inputAreaStep + 12
- left: addressLine.left
- right: addressLine.right
+ top: parent.top;
+ left: addressLineContainer.left;
+ right: addressLineContainer.right;
}
}
+
HifiStyles.FiraSansRegular {
id: location;
+ anchors {
+ left: addressLineContainer.left;
+ leftMargin: 8;
+ verticalCenter: addressLineContainer.verticalCenter;
+ }
font.pixelSize: addressLine.font.pixelSize;
color: "gray";
clip: true;
- anchors.fill: addressLine;
visible: addressLine.text.length === 0
}
TextInput {
id: addressLine
- focus: true
+ width: addressLineContainer.width - addressLineContainer.anchors.leftMargin - addressLineContainer.anchors.rightMargin;
anchors {
- bottom: parent.bottom
- left: parent.left
- right: parent.right
- leftMargin: 16
- rightMargin: 16
- topMargin: parent.inputAreaStep + (2 * hifi.layout.spacing)
- bottomMargin: parent.inputAreaStep
+ left: addressLineContainer.left;
+ leftMargin: 8;
+ verticalCenter: addressLineContainer.verticalCenter;
}
font.pixelSize: hifi.fonts.pixelSize * 0.75
- cursorVisible: false
onTextChanged: {
filterChoicesByText();
updateLocationText(text.length > 0);
- if (!isCursorVisible && text.length > 0) {
- isCursorVisible = true;
- cursorVisible = true;
- }
}
onAccepted: {
addressBarDialog.keyboardEnabled = false;
- }
- onActiveFocusChanged: {
- cursorVisible = isCursorVisible && focus;
- }
- MouseArea {
- // If user clicks in address bar show cursor to indicate ability to enter address.
- anchors.fill: parent
- onClicked: {
- isCursorVisible = true;
- parent.cursorVisible = true;
- parent.focus = true;
- parent.forceActiveFocus();
- addressBarDialog.keyboardEnabled = HMD.active
- tabletRoot.playButtonClickSound();
- }
+ toggleOrGo();
}
}
Rectangle {
- anchors.fill: addressLine
+ id: addressLineContainer;
+ height: 40;
+ anchors {
+ top: notice.bottom;
+ topMargin: 2;
+ left: parent.left;
+ leftMargin: 16;
+ right: parent.right;
+ rightMargin: 16;
+ }
color: hifiStyleConstants.colors.lightGray
opacity: 0.1
+ MouseArea {
+ anchors.fill: parent;
+ onClicked: {
+ if (!addressLine.focus || !HMD.active) {
+ addressLine.focus = true;
+ addressLine.forceActiveFocus();
+ addressBarDialog.keyboardEnabled = HMD.active;
+ }
+ tabletRoot.playButtonClickSound();
+ }
+ }
}
}
Rectangle {
@@ -347,13 +341,12 @@ StackView {
Timer {
// Delay clearing address line so as to avoid flicker of "not connected" being displayed after entering an address.
- id: clearAddressLineTimer
- running: false
- interval: 100 // ms
- repeat: false
+ id: clearAddressLineTimer;
+ running: false;
+ interval: 100; // ms
+ repeat: false;
onTriggered: {
addressLine.text = "";
- isCursorVisible = false;
}
}
@@ -535,7 +528,7 @@ StackView {
function updateLocationText(enteringAddress) {
if (enteringAddress) {
- notice.text = "Go to a place, @user, path or network address";
+ notice.text = "Go To a place, @user, path, or network address:";
notice.color = hifiStyleConstants.colors.baseGrayHighlight;
} else {
notice.text = AddressManager.isConnected ? "Your location:" : "Not Connected";
@@ -545,46 +538,14 @@ StackView {
}
}
- onVisibleChanged: {
- updateLocationText(false);
- if (visible) {
- addressLine.forceActiveFocus();
- fillDestinations();
- }
- }
-
function toggleOrGo(fromSuggestions, address) {
if (address !== undefined && address !== "") {
- addressBarDialog.loadAddress(address, fromSuggestions)
- }
-
- if (addressLine.text !== "") {
- addressBarDialog.loadAddress(addressLine.text, fromSuggestions)
- }
-
- if (isDesktop) {
- tablet.gotoHomeScreen();
- } else {
- HMD.closeTablet();
- }
-
- tabletRoot.shown = false;
- }
-
- Keys.onPressed: {
- switch (event.key) {
- case Qt.Key_Escape:
- case Qt.Key_Back:
- tabletRoot.shown = false
- clearAddressLineTimer.start();
- event.accepted = true
- break
- case Qt.Key_Enter:
- case Qt.Key_Return:
- toggleOrGo()
- clearAddressLineTimer.start();
- event.accepted = true
- break
+ addressBarDialog.loadAddress(address, fromSuggestions);
+ clearAddressLineTimer.start();
+ } else if (addressLine.text !== "") {
+ addressBarDialog.loadAddress(addressLine.text, fromSuggestions);
+ clearAddressLineTimer.start();
}
+ DialogsManager.hideAddressBar();
}
}
diff --git a/interface/resources/qml/hifi/tablet/TabletStoryCard.qml b/interface/resources/qml/hifi/tablet/TabletStoryCard.qml
deleted file mode 100644
index 1d57c8a083..0000000000
--- a/interface/resources/qml/hifi/tablet/TabletStoryCard.qml
+++ /dev/null
@@ -1,46 +0,0 @@
-//
-// TabletAddressDialog.qml
-//
-// Created by Dante Ruiz on 2017/04/24
-// Copyright 2015 High Fidelity, Inc.
-//
-// Distributed under the Apache License, Version 2.0.
-// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-import Hifi 1.0
-import QtQuick 2.4
-import QtGraphicalEffects 1.0
-import "../../controls"
-import "../../styles"
-import "../../windows"
-import "../"
-import "../toolbars"
-import "../../styles-uit" as HifiStyles
-import "../../controls-uit" as HifiControlsUit
-import "../../controls" as HifiControls
-
-
-Rectangle {
- id: cardRoot
- HifiStyles.HifiConstants { id: hifi }
- width: parent.width
- height: parent.height
- property string address: ""
- property alias eventBridge: webview.eventBridge
- function setUrl(url) {
- cardRoot.address = url;
- webview.url = url;
- }
-
- HifiControls.TabletWebView {
- id: webview
- parentStackItem: root
- anchors {
- top: parent.top
- right: parent.right
- left: parent.left
- bottom: parent.bottom
- }
- }
-}
diff --git a/interface/resources/qml/hifi/toolbars/ToolbarButton.qml b/interface/resources/qml/hifi/toolbars/ToolbarButton.qml
index cab5b14d5c..3d4231ced7 100644
--- a/interface/resources/qml/hifi/toolbars/ToolbarButton.qml
+++ b/interface/resources/qml/hifi/toolbars/ToolbarButton.qml
@@ -3,6 +3,8 @@ import QtQuick.Controls 1.4
StateImage {
id: button
+
+ property bool buttonEnabled: true
property bool isActive: false
property bool isEntered: false
@@ -39,30 +41,37 @@ StateImage {
}
function updateState() {
- if (!button.isEntered && !button.isActive) {
- buttonState = imageOffOut;
- } else if (!button.isEntered && button.isActive) {
- buttonState = imageOnOut;
- } else if (button.isEntered && !button.isActive) {
- buttonState = imageOffIn;
+ if (buttonEnabled) {
+ if (!button.isEntered && !button.isActive) {
+ buttonState = imageOffOut;
+ } else if (!button.isEntered && button.isActive) {
+ buttonState = imageOnOut;
+ } else if (button.isEntered && !button.isActive) {
+ buttonState = imageOffIn;
+ } else {
+ buttonState = imageOnIn;
+ }
} else {
- buttonState = imageOnIn;
+ buttonState = 0;
}
}
onIsActiveChanged: updateState();
+ onButtonEnabledChanged: updateState();
Timer {
id: asyncClickSender
interval: 10
repeat: false
running: false
- onTriggered: button.clicked();
+ onTriggered: {
+ button.clicked();
+ }
}
MouseArea {
id: mouseArea
- hoverEnabled: true
+ hoverEnabled: buttonEnabled
anchors.fill: parent
onClicked: asyncClickSender.start();
onEntered: {
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index c6cd185034..88278034d0 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -1420,11 +1420,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
connect(DependencyManager::get().data(), &AudioClient::mutedByMixer, this, onMutedByMixer);
// Track when the address bar is opened
- auto onAddressBarToggled = [this]() {
+ auto onAddressBarShown = [this]() {
// Record time
UserActivityLogger::getInstance().logAction("opened_address_bar", { { "uptime_ms", _sessionRunTimer.elapsed() } });
};
- connect(DependencyManager::get().data(), &DialogsManager::addressBarToggled, this, onAddressBarToggled);
+ connect(DependencyManager::get().data(), &DialogsManager::addressBarShown, this, onAddressBarShown);
// Make sure we don't time out during slow operations at startup
updateHeartbeat();
diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp
index 23d689e339..2451f42bca 100644
--- a/interface/src/Menu.cpp
+++ b/interface/src/Menu.cpp
@@ -254,7 +254,7 @@ Menu::Menu() {
// Navigate > Show Address Bar
addActionToQMenuAndActionHash(navigateMenu, MenuOption::AddressBar, Qt::CTRL | Qt::Key_L,
- dialogsManager.data(), SLOT(toggleAddressBar()));
+ dialogsManager.data(), SLOT(showAddressBar()));
// Navigate > Bookmark related menus -- Note: the Bookmark class adds its own submenus here.
qApp->getBookmarks()->setupMenus(this, navigateMenu);
diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp
index 083b513a31..b4d5fea360 100644
--- a/interface/src/avatar/Avatar.cpp
+++ b/interface/src/avatar/Avatar.cpp
@@ -96,6 +96,14 @@ Avatar::Avatar(RigPointer rig) :
_lastOrientation(),
_worldUpDirection(DEFAULT_UP_DIRECTION),
_moving(false),
+ _smoothPositionTime(SMOOTH_TIME_POSITION),
+ _smoothPositionTimer(std::numeric_limits::max()),
+ _smoothOrientationTime(SMOOTH_TIME_ORIENTATION),
+ _smoothOrientationTimer(std::numeric_limits::max()),
+ _smoothPositionInitial(),
+ _smoothPositionTarget(),
+ _smoothOrientationInitial(),
+ _smoothOrientationTarget(),
_initialized(false),
_voiceSphereID(GeometryCache::UNKNOWN_ID)
{
@@ -349,6 +357,33 @@ void Avatar::simulate(float deltaTime, bool inView) {
_simulationInViewRate.increment();
}
+ if (!isMyAvatar()) {
+ if (_smoothPositionTimer < _smoothPositionTime) {
+ // Smooth the remote avatar movement.
+ _smoothPositionTimer += deltaTime;
+ if (_smoothPositionTimer < _smoothPositionTime) {
+ AvatarData::setPosition(
+ lerp(_smoothPositionInitial,
+ _smoothPositionTarget,
+ easeInOutQuad(glm::clamp(_smoothPositionTimer / _smoothPositionTime, 0.0f, 1.0f)))
+ );
+ updateAttitude();
+ }
+ }
+
+ if (_smoothOrientationTimer < _smoothOrientationTime) {
+ // Smooth the remote avatar movement.
+ _smoothOrientationTimer += deltaTime;
+ if (_smoothOrientationTimer < _smoothOrientationTime) {
+ AvatarData::setOrientation(
+ slerp(_smoothOrientationInitial,
+ _smoothOrientationTarget,
+ easeInOutQuad(glm::clamp(_smoothOrientationTimer / _smoothOrientationTime, 0.0f, 1.0f)))
+ );
+ updateAttitude();
+ }
+ }
+ }
PerformanceTimer perfTimer("simulate");
{
@@ -1361,13 +1396,31 @@ glm::quat Avatar::getUncachedRightPalmRotation() const {
}
void Avatar::setPosition(const glm::vec3& position) {
- AvatarData::setPosition(position);
- updateAttitude();
+ if (isMyAvatar()) {
+ // This is the local avatar, no need to handle any position smoothing.
+ AvatarData::setPosition(position);
+ updateAttitude();
+ return;
+ }
+
+ // Whether or not there is an existing smoothing going on, just reset the smoothing timer and set the starting position as the avatar's current position, then smooth to the new position.
+ _smoothPositionInitial = getPosition();
+ _smoothPositionTarget = position;
+ _smoothPositionTimer = 0.0f;
}
void Avatar::setOrientation(const glm::quat& orientation) {
- AvatarData::setOrientation(orientation);
- updateAttitude();
+ if (isMyAvatar()) {
+ // This is the local avatar, no need to handle any position smoothing.
+ AvatarData::setOrientation(orientation);
+ updateAttitude();
+ return;
+ }
+
+ // Whether or not there is an existing smoothing going on, just reset the smoothing timer and set the starting position as the avatar's current position, then smooth to the new position.
+ _smoothOrientationInitial = getOrientation();
+ _smoothOrientationTarget = orientation;
+ _smoothOrientationTimer = 0.0f;
}
void Avatar::updatePalms() {
diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h
index 3e55bedc38..7b9d331048 100644
--- a/interface/src/avatar/Avatar.h
+++ b/interface/src/avatar/Avatar.h
@@ -230,6 +230,16 @@ public:
bool hasNewJointData() const { return _hasNewJointData; }
+ inline float easeInOutQuad(float lerpValue) {
+ assert(!((lerpValue < 0.0f) || (lerpValue > 1.0f)));
+
+ if (lerpValue < 0.5f) {
+ return (2.0f * lerpValue * lerpValue);
+ }
+
+ return (lerpValue*(4.0f - 2.0f * lerpValue) - 1.0f);
+ }
+
public slots:
// FIXME - these should be migrated to use Pose data instead
@@ -244,6 +254,9 @@ public slots:
protected:
friend class AvatarManager;
+ const float SMOOTH_TIME_POSITION = 0.125f;
+ const float SMOOTH_TIME_ORIENTATION = 0.075f;
+
virtual const QString& getSessionDisplayNameForTransport() const override { return _empty; } // Save a tiny bit of bandwidth. Mixer won't look at what we send.
QString _empty{};
virtual void maybeUpdateSessionDisplayNameFromTransport(const QString& sessionDisplayName) override { _sessionDisplayName = sessionDisplayName; } // don't use no-op setter!
@@ -313,6 +326,15 @@ protected:
RateCounter<> _skeletonModelSimulationRate;
RateCounter<> _jointDataSimulationRate;
+ // Smoothing data for blending from one position/orientation to another on remote agents.
+ float _smoothPositionTime;
+ float _smoothPositionTimer;
+ float _smoothOrientationTime;
+ float _smoothOrientationTimer;
+ glm::vec3 _smoothPositionInitial;
+ glm::vec3 _smoothPositionTarget;
+ glm::quat _smoothOrientationInitial;
+ glm::quat _smoothOrientationTarget;
private:
class AvatarEntityDataHash {
diff --git a/interface/src/networking/HFTabletWebEngineRequestInterceptor.cpp b/interface/src/networking/HFTabletWebEngineRequestInterceptor.cpp
index 7282fb5e3d..fd79fc1cb6 100644
--- a/interface/src/networking/HFTabletWebEngineRequestInterceptor.cpp
+++ b/interface/src/networking/HFTabletWebEngineRequestInterceptor.cpp
@@ -34,9 +34,13 @@ void HFTabletWebEngineRequestInterceptor::interceptRequest(QWebEngineUrlRequestI
QString bearerTokenString = "Bearer " + accountManager->getAccountInfo().getAccessToken().token;
info.setHttpHeader(OAUTH_AUTHORIZATION_HEADER.toLocal8Bit(), bearerTokenString.toLocal8Bit());
}
- }
- static const QString USER_AGENT = "User-Agent";
- QString tokenString = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36";
- info.setHttpHeader(USER_AGENT.toLocal8Bit(), tokenString.toLocal8Bit());
+ static const QString USER_AGENT = "User-Agent";
+ QString tokenString = "Chrome/48.0 (HighFidelityInterface)";
+ info.setHttpHeader(USER_AGENT.toLocal8Bit(), tokenString.toLocal8Bit());
+ } else {
+ static const QString USER_AGENT = "User-Agent";
+ QString tokenString = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36";
+ info.setHttpHeader(USER_AGENT.toLocal8Bit(), tokenString.toLocal8Bit());
+ }
}
diff --git a/interface/src/scripting/DialogsManagerScriptingInterface.cpp b/interface/src/scripting/DialogsManagerScriptingInterface.cpp
index 1604c45593..0fb6078290 100644
--- a/interface/src/scripting/DialogsManagerScriptingInterface.cpp
+++ b/interface/src/scripting/DialogsManagerScriptingInterface.cpp
@@ -16,15 +16,24 @@
#include "ui/DialogsManager.h"
DialogsManagerScriptingInterface::DialogsManagerScriptingInterface() {
- connect(DependencyManager::get().data(), &DialogsManager::addressBarToggled,
- this, &DialogsManagerScriptingInterface::addressBarToggled);
connect(DependencyManager::get().data(), &DialogsManager::addressBarShown,
this, &DialogsManagerScriptingInterface::addressBarShown);
}
-void DialogsManagerScriptingInterface::toggleAddressBar() {
+
+DialogsManagerScriptingInterface* DialogsManagerScriptingInterface::getInstance() {
+ static DialogsManagerScriptingInterface sharedInstance;
+ return &sharedInstance;
+}
+
+void DialogsManagerScriptingInterface::showAddressBar() {
QMetaObject::invokeMethod(DependencyManager::get().data(),
- "toggleAddressBar", Qt::QueuedConnection);
+ "showAddressBar", Qt::QueuedConnection);
+}
+
+void DialogsManagerScriptingInterface::hideAddressBar() {
+ QMetaObject::invokeMethod(DependencyManager::get().data(),
+ "hideAddressBar", Qt::QueuedConnection);
}
void DialogsManagerScriptingInterface::showFeed() {
diff --git a/interface/src/scripting/DialogsManagerScriptingInterface.h b/interface/src/scripting/DialogsManagerScriptingInterface.h
index 86cd22af1c..e4dd18aedf 100644
--- a/interface/src/scripting/DialogsManagerScriptingInterface.h
+++ b/interface/src/scripting/DialogsManagerScriptingInterface.h
@@ -18,13 +18,14 @@ class DialogsManagerScriptingInterface : public QObject {
Q_OBJECT
public:
DialogsManagerScriptingInterface();
+ static DialogsManagerScriptingInterface* getInstance();
Q_INVOKABLE void showFeed();
public slots:
- void toggleAddressBar();
+ void showAddressBar();
+ void hideAddressBar();
signals:
- void addressBarToggled();
void addressBarShown(bool visible);
};
diff --git a/interface/src/ui/DialogsManager.cpp b/interface/src/ui/DialogsManager.cpp
index a95ac8d91f..96b5da3a55 100644
--- a/interface/src/ui/DialogsManager.cpp
+++ b/interface/src/ui/DialogsManager.cpp
@@ -46,49 +46,32 @@ void DialogsManager::maybeCreateDialog(QPointer& member) {
}
}
-void DialogsManager::toggleAddressBar() {
- auto hmd = DependencyManager::get();
- auto tabletScriptingInterface = DependencyManager::get();
- auto tablet = dynamic_cast(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
- if (tablet->getToolbarMode()) {
- if (tablet->isPathLoaded(TABLET_ADDRESS_DIALOG)) {
- tablet->gotoHomeScreen();
- emit addressBarToggled();
- } else {
- tablet->loadQMLSource(TABLET_ADDRESS_DIALOG);
- emit addressBarToggled();
- }
- } else {
- if (hmd->getShouldShowTablet()) {
- if (tablet->isPathLoaded(TABLET_ADDRESS_DIALOG) && _closeAddressBar) {
- tablet->gotoHomeScreen();
- hmd->closeTablet();
- _closeAddressBar = false;
- emit addressBarToggled();
- } else {
- tablet->loadQMLSource(TABLET_ADDRESS_DIALOG);
- _closeAddressBar = true;
- emit addressBarToggled();
- }
- } else {
- tablet->loadQMLSource(TABLET_ADDRESS_DIALOG);
- hmd->openTablet();
- _closeAddressBar = true;
- emit addressBarToggled();
- }
-
- }
-}
-
void DialogsManager::showAddressBar() {
auto hmd = DependencyManager::get();
auto tabletScriptingInterface = DependencyManager::get();
auto tablet = dynamic_cast(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
- tablet->loadQMLSource(TABLET_ADDRESS_DIALOG);
+ if (!tablet->isPathLoaded(TABLET_ADDRESS_DIALOG)) {
+ tablet->loadQMLSource(TABLET_ADDRESS_DIALOG);
+ }
if (!hmd->getShouldShowTablet()) {
hmd->openTablet();
}
+ qApp->setKeyboardFocusOverlay(hmd->getCurrentTabletScreenID());
+ emit addressBarShown(true);
+}
+
+void DialogsManager::hideAddressBar() {
+ auto hmd = DependencyManager::get();
+ auto tabletScriptingInterface = DependencyManager::get();
+ auto tablet = dynamic_cast(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
+
+ if (tablet->isPathLoaded(TABLET_ADDRESS_DIALOG)) {
+ tablet->gotoHomeScreen();
+ hmd->closeTablet();
+ }
+ qApp->setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID);
+ emit addressBarShown(false);
}
void DialogsManager::showFeed() {
diff --git a/interface/src/ui/DialogsManager.h b/interface/src/ui/DialogsManager.h
index 24b9078baf..3a40b15a3b 100644
--- a/interface/src/ui/DialogsManager.h
+++ b/interface/src/ui/DialogsManager.h
@@ -41,8 +41,8 @@ public:
void emitAddressBarShown(bool visible) { emit addressBarShown(visible); }
public slots:
- void toggleAddressBar();
void showAddressBar();
+ void hideAddressBar();
void showFeed();
void setDomainConnectionFailureVisibility(bool visible);
void toggleLoginDialog();
@@ -57,7 +57,6 @@ public slots:
void showUpdateDialog();
signals:
- void addressBarToggled();
void addressBarShown(bool visible);
void setUseFeed(bool useFeed);
diff --git a/interface/src/ui/SnapshotUploader.cpp b/interface/src/ui/SnapshotUploader.cpp
index 5826c8bd38..411e892de5 100644
--- a/interface/src/ui/SnapshotUploader.cpp
+++ b/interface/src/ui/SnapshotUploader.cpp
@@ -40,6 +40,9 @@ void SnapshotUploader::uploadSuccess(QNetworkReply& reply) {
QJsonObject userStoryObject;
QJsonObject detailsObject;
detailsObject.insert("image_url", imageUrl);
+ if (dataObject.contains("shareable_url")) {
+ detailsObject.insert("shareable_url", dataObject.value("shareable_url").toString());
+ }
QString pickledDetails = QJsonDocument(detailsObject).toJson();
userStoryObject.insert("details", pickledDetails);
userStoryObject.insert("thumbnail_url", thumbnailUrl);
diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp
index 502006c862..f80589e5a1 100644
--- a/interface/src/ui/overlays/Web3DOverlay.cpp
+++ b/interface/src/ui/overlays/Web3DOverlay.cpp
@@ -198,6 +198,7 @@ void Web3DOverlay::loadSourceURL() {
_webSurface->getRootContext()->setContextProperty("AvatarInputs", AvatarInputs::getInstance());
_webSurface->getRootContext()->setContextProperty("GlobalServices", GlobalServicesScriptingInterface::getInstance());
_webSurface->getRootContext()->setContextProperty("AvatarList", DependencyManager::get().data());
+ _webSurface->getRootContext()->setContextProperty("DialogsManager", DialogsManagerScriptingInterface::getInstance());
_webSurface->getRootContext()->setContextProperty("pathToFonts", "../../");
tabletScriptingInterface->setQmlTabletRoot("com.highfidelity.interface.tablet.system", _webSurface->getRootItem(), _webSurface.data());
diff --git a/libraries/avatars/src/AvatarHashMap.h b/libraries/avatars/src/AvatarHashMap.h
index 87bedf8d51..e944c7c887 100644
--- a/libraries/avatars/src/AvatarHashMap.h
+++ b/libraries/avatars/src/AvatarHashMap.h
@@ -41,7 +41,7 @@ public:
Q_INVOKABLE QVector getAvatarIdentifiers();
// Null/Default-constructed QUuids will return MyAvatar
- virtual ScriptAvatarData* getAvatar(QUuid avatarID) { return new ScriptAvatarData(getAvatarBySessionID(avatarID)); }
+ Q_INVOKABLE virtual ScriptAvatarData* getAvatar(QUuid avatarID) { return new ScriptAvatarData(getAvatarBySessionID(avatarID)); }
virtual AvatarSharedPointer getAvatarBySessionID(const QUuid& sessionID) const { return findAvatar(sessionID); }
int numberOfAvatarsInRange(const glm::vec3& position, float rangeMeters);