diff --git a/interface/resources/images/hifi-logo-blackish.svg b/interface/resources/images/hifi-logo-blackish.svg new file mode 100644 index 0000000000..60bfb3d418 --- /dev/null +++ b/interface/resources/images/hifi-logo-blackish.svg @@ -0,0 +1,123 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/interface/resources/images/login-close.svg b/interface/resources/images/login-close.svg new file mode 100644 index 0000000000..2fb10c241b --- /dev/null +++ b/interface/resources/images/login-close.svg @@ -0,0 +1,55 @@ + +image/svg+xml \ No newline at end of file diff --git a/interface/resources/images/login-password.svg b/interface/resources/images/login-password.svg new file mode 100644 index 0000000000..98d86f6d8a --- /dev/null +++ b/interface/resources/images/login-password.svg @@ -0,0 +1,58 @@ + +image/svg+xml \ No newline at end of file diff --git a/interface/resources/images/login-username.svg b/interface/resources/images/login-username.svg new file mode 100644 index 0000000000..a40dd91cf7 --- /dev/null +++ b/interface/resources/images/login-username.svg @@ -0,0 +1,51 @@ + +image/svg+xml \ No newline at end of file diff --git a/interface/resources/qml/AddressBarDialog.qml b/interface/resources/qml/AddressBarDialog.qml index 91e05d020d..3377b20d87 100644 --- a/interface/resources/qml/AddressBarDialog.qml +++ b/interface/resources/qml/AddressBarDialog.qml @@ -9,18 +9,16 @@ // import Hifi 1.0 -import QtQuick 2.3 -import QtQuick.Controls 1.2 +import QtQuick 2.4 import "controls" import "styles" -Item { +DialogContainer { id: root HifiConstants { id: hifi } objectName: "AddressBarDialog" - property int animationDuration: hifi.effects.fadeInDuration property bool destroyOnInvisible: false property real scale: 1.25 // Make this dialog a little larger than normal @@ -101,47 +99,16 @@ Item { } } - // The UI enables an object, rather than manipulating its visibility, so that we can do animations in both directions. - // Because visibility and enabled are booleans, they cannot be animated. So when enabled is changed, we modify a property - // that can be animated, like scale or opacity, and then when the target animation value is reached, we can modify the - // visibility. - enabled: false - opacity: 0.0 - onEnabledChanged: { - opacity = enabled ? 1.0 : 0.0 if (enabled) { - addressLine.forceActiveFocus(); + addressLine.forceActiveFocus() } } - Behavior on opacity { - // Animate opacity. - NumberAnimation { - duration: animationDuration - easing.type: Easing.OutCubic - } - } - - onOpacityChanged: { - // Once we're transparent, disable the dialog's visibility. - visible = (opacity != 0.0) - } - onVisibleChanged: { if (!visible) { - reset() - - // Some dialogs should be destroyed when they become invisible. - if (destroyOnInvisible) { - destroy() - } + addressLine.text = "" } - - } - - function reset() { - addressLine.text = "" } function toggleOrGo() { @@ -152,21 +119,18 @@ Item { } } - Keys.onEscapePressed: { - enabled = false - } - Keys.onPressed: { - switch(event.key) { - case Qt.Key_W: - if (event.modifiers == Qt.ControlModifier) { - event.accepted = true - enabled = false - } + switch (event.key) { + case Qt.Key_Escape: + case Qt.Key_Back: + enabled = false + event.accepted = true + break + case Qt.Key_Enter: + case Qt.Key_Return: + toggleOrGo() + event.accepted = true break } } - - Keys.onReturnPressed: toggleOrGo() - Keys.onEnterPressed: toggleOrGo() } diff --git a/interface/resources/qml/Browser.qml b/interface/resources/qml/Browser.qml index 55a0a6a461..947bf739fc 100644 --- a/interface/resources/qml/Browser.qml +++ b/interface/resources/qml/Browser.qml @@ -4,7 +4,7 @@ import QtWebKit 3.0 import "controls" import "styles" -Dialog { +VrDialog { id: root HifiConstants { id: hifi } title: "Browser" diff --git a/interface/resources/qml/ErrorDialog.qml b/interface/resources/qml/ErrorDialog.qml index c0f8132f14..76d9111d97 100644 --- a/interface/resources/qml/ErrorDialog.qml +++ b/interface/resources/qml/ErrorDialog.qml @@ -8,27 +8,22 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -import Hifi 1.0 as Hifi -import QtQuick 2.3 -import QtQuick.Controls 1.2 -import QtQuick.Dialogs 1.2 +import Hifi 1.0 +import QtQuick 2.4 import "controls" import "styles" -Item { +DialogContainer { id: root HifiConstants { id: hifi } - property int animationDuration: hifi.effects.fadeInDuration - property bool destroyOnInvisible: true - Component.onCompleted: { enabled = true } onParentChanged: { if (visible && enabled) { - forceActiveFocus(); + forceActiveFocus() } } @@ -38,7 +33,7 @@ Item { x: parent ? parent.width / 2 - width / 2 : 0 y: parent ? parent.height / 2 - height / 2 : 0 - Hifi.ErrorDialog { + ErrorDialog { id: content implicitWidth: box.width @@ -69,7 +64,7 @@ Item { Text { id: messageText - font.pointSize: 10 + font.pixelSize: hifi.fonts.pixelSize * 0.6 font.weight: Font.Bold anchors { @@ -91,55 +86,17 @@ Item { } MouseArea { anchors.fill: parent + cursorShape: "PointingHandCursor" onClicked: { - content.accept(); + content.accept() } } } } } - // The UI enables an object, rather than manipulating its visibility, so that we can do animations in both directions. - // Because visibility and enabled are booleans, they cannot be animated. So when enabled is changed, we modify a property - // that can be animated, like scale or opacity, and then when the target animation value is reached, we can modify the - // visibility. - enabled: false - opacity: 0.0 - - onEnabledChanged: { - opacity = enabled ? 1.0 : 0.0 - } - - Behavior on opacity { - // Animate opacity. - NumberAnimation { - duration: animationDuration - easing.type: Easing.OutCubic - } - } - - onOpacityChanged: { - // Once we're transparent, disable the dialog's visibility. - visible = (opacity != 0.0) - } - - onVisibleChanged: { - if (!visible) { - // Some dialogs should be destroyed when they become invisible. - if (destroyOnInvisible) { - destroy() - } - } - } - Keys.onPressed: { - if (event.modifiers === Qt.ControlModifier) - switch (event.key) { - case Qt.Key_W: - event.accepted = true - content.accept() - break - } else switch (event.key) { + switch (event.key) { case Qt.Key_Escape: case Qt.Key_Back: case Qt.Key_Enter: diff --git a/interface/resources/qml/InfoView.qml b/interface/resources/qml/InfoView.qml index 6b49e6f0c7..012f04f1fd 100644 --- a/interface/resources/qml/InfoView.qml +++ b/interface/resources/qml/InfoView.qml @@ -5,7 +5,7 @@ import QtQuick.Controls.Styles 1.3 import QtWebKit 3.0 import "controls" -Dialog { +VrDialog { id: root width: 800 height: 800 diff --git a/interface/resources/qml/LoginDialog.qml b/interface/resources/qml/LoginDialog.qml index 5653dfc7a1..8d5267f7f8 100644 --- a/interface/resources/qml/LoginDialog.qml +++ b/interface/resources/qml/LoginDialog.qml @@ -1,78 +1,173 @@ +// +// LoginDialog.qml +// +// Created by David Rowe on 3 Jun 2015 +// 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.3 -import QtQuick.Controls.Styles 1.3 +import QtQuick 2.4 import "controls" import "styles" -Dialog { +DialogContainer { + id: root HifiConstants { id: hifi } - title: "Login" + objectName: "LoginDialog" - height: 512 - width: 384 - onVisibleChanged: { - if (!visible) { - reset() - } - } + property bool destroyOnInvisible: false - onEnabledChanged: { - if (enabled) { - username.forceActiveFocus(); - } - } + implicitWidth: loginDialog.implicitWidth + implicitHeight: loginDialog.implicitHeight - function reset() { - username.text = "" - password.text = "" - loginDialog.statusText = "" - } + x: parent ? parent.width / 2 - width / 2 : 0 + y: parent ? parent.height / 2 - height / 2 : 0 + property int maximumX: parent ? parent.width - width : 0 + property int maximumY: parent ? parent.height - height : 0 LoginDialog { id: loginDialog - anchors.fill: parent - anchors.margins: parent.margins - anchors.topMargin: parent.topMargin - Column { - anchors.topMargin: 8 - anchors.right: parent.right - anchors.rightMargin: 0 - anchors.left: parent.left - anchors.top: parent.top - spacing: 8 - Image { - height: 64 - anchors.horizontalCenter: parent.horizontalCenter - width: 64 - source: "../images/hifi-logo.svg" + implicitWidth: backgroundRectangle.width + implicitHeight: backgroundRectangle.height + + readonly property int inputWidth: 500 + readonly property int inputHeight: 60 + readonly property int borderWidth: 30 + readonly property int closeMargin: 16 + readonly property real tan30: 0.577 // tan(30°) + readonly property int inputSpacing: 16 + property int maximumX: parent ? parent.width - width : 0 + property int maximumY: parent ? parent.height - height : 0 + + Rectangle { + id: backgroundRectangle + width: loginDialog.inputWidth + loginDialog.borderWidth * 2 + height: loginDialog.inputHeight * 6 + loginDialog.closeMargin * 2 + radius: loginDialog.closeMargin * 2 + + color: "#2c86b1" + opacity: 0.85 + + MouseArea { + width: parent.width + height: parent.height + anchors { + horizontalCenter: parent.horizontalCenter + verticalCenter: parent.verticalCenter + } + drag { + target: root + minimumX: 0 + minimumY: 0 + maximumX: root.parent ? root.maximumX : 0 + maximumY: root.parent ? root.maximumY : 0 + } + } + } + + Image { + id: closeIcon + source: "../images/login-close.svg" + width: 20 + height: 20 + anchors { + top: backgroundRectangle.top + right: backgroundRectangle.right + topMargin: loginDialog.closeMargin + rightMargin: loginDialog.closeMargin } - Border { - width: 304 - height: 64 - anchors.horizontalCenter: parent.horizontalCenter + MouseArea { + anchors.fill: parent + cursorShape: "PointingHandCursor" + onClicked: { + root.enabled = false + } + } + } + + Column { + id: mainContent + width: loginDialog.inputWidth + spacing: loginDialog.inputSpacing + anchors { + horizontalCenter: parent.horizontalCenter + verticalCenter: parent.verticalCenter + } + + Item { + // Offset content down a little + width: loginDialog.inputWidth + height: loginDialog.closeMargin + } + + Rectangle { + width: loginDialog.inputWidth + height: loginDialog.inputHeight + radius: height / 2 + color: "#ebebeb" + + Image { + source: "../images/login-username.svg" + width: loginDialog.inputHeight * 0.65 + height: width + anchors { + verticalCenter: parent.verticalCenter + left: parent.left + leftMargin: loginDialog.inputHeight / 4 + } + } + TextInput { id: username - anchors.fill: parent - helperText: "Username or Email" - anchors.margins: 8 + anchors { + fill: parent + leftMargin: loginDialog.inputHeight + rightMargin: loginDialog.inputHeight / 2 + } + + helperText: "username or email" + color: hifi.colors.text + KeyNavigation.tab: password KeyNavigation.backtab: password } } - Border { - width: 304 - height: 64 - anchors.horizontalCenter: parent.horizontalCenter + Rectangle { + width: loginDialog.inputWidth + height: loginDialog.inputHeight + radius: height / 2 + color: "#ebebeb" + + Image { + source: "../images/login-password.svg" + width: loginDialog.inputHeight * 0.65 + height: width + anchors { + verticalCenter: parent.verticalCenter + left: parent.left + leftMargin: loginDialog.inputHeight / 4 + } + } + TextInput { id: password - anchors.fill: parent + anchors { + fill: parent + leftMargin: loginDialog.inputHeight + rightMargin: loginDialog.inputHeight / 2 + } + + helperText: "password" echoMode: TextInput.Password - helperText: "Password" - anchors.margins: 8 + color: hifi.colors.text + KeyNavigation.tab: username KeyNavigation.backtab: username onFocusChanged: { @@ -83,102 +178,176 @@ Dialog { } } - Text { - anchors.horizontalCenter: parent.horizontalCenter - textFormat: Text.StyledText - width: parent.width - height: 96 - wrapMode: Text.WordWrap - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - text: loginDialog.statusText - } - } + Item { + width: loginDialog.inputWidth + height: loginDialog.inputHeight / 2 - Column { - anchors.bottomMargin: 5 - anchors.right: parent.right - anchors.rightMargin: 0 - anchors.left: parent.left - anchors.bottom: parent.bottom + Text { + id: messageText + + visible: loginDialog.statusText != "" && loginDialog.statusText != "Logging in..." + + width: loginDialog.inputWidth + height: loginDialog.inputHeight / 2 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + + text: loginDialog.statusText + color: "white" + } + + Row { + id: messageSpinner + + visible: loginDialog.statusText == "Logging in..." + onVisibleChanged: visible ? messageSpinnerAnimation.restart() : messageSpinnerAnimation.stop() + + spacing: 24 + anchors { + verticalCenter: parent.verticalCenter + horizontalCenter: parent.horizontalCenter + } + + Rectangle { + id: spinner1 + width: 10 + height: 10 + color: "#ebebeb" + opacity: 0.05 + } + + Rectangle { + id: spinner2 + width: 10 + height: 10 + color: "#ebebeb" + opacity: 0.05 + } + + Rectangle { + id: spinner3 + width: 10 + height: 10 + color: "#ebebeb" + opacity: 0.05 + } + + SequentialAnimation { + id: messageSpinnerAnimation + running: messageSpinner.visible + loops: Animation.Infinite + NumberAnimation { target: spinner1; property: "opacity"; to: 1.0; duration: 1000 } + NumberAnimation { target: spinner2; property: "opacity"; to: 1.0; duration: 1000 } + NumberAnimation { target: spinner3; property: "opacity"; to: 1.0; duration: 1000 } + NumberAnimation { target: spinner1; property: "opacity"; to: 0.05; duration: 0 } + NumberAnimation { target: spinner2; property: "opacity"; to: 0.05; duration: 0 } + NumberAnimation { target: spinner3; property: "opacity"; to: 0.05; duration: 0 } + } + } + } Rectangle { - width: 192 - height: 64 - anchors.horizontalCenter: parent.horizontalCenter - color: hifi.colors.hifiBlue - border.width: 0 - radius: 10 + width: loginDialog.inputWidth + height: loginDialog.inputHeight + radius: height / 2 + color: "#353535" + + TextInput { + anchors.fill: parent + text: "Login" + color: "white" + horizontalAlignment: Text.AlignHCenter + } MouseArea { - anchors.bottom: parent.bottom - anchors.bottomMargin: 0 - anchors.top: parent.top - anchors.right: parent.right - anchors.left: parent.left + anchors.fill: parent + cursorShape: "PointingHandCursor" onClicked: { loginDialog.login(username.text, password.text) } } + } - Row { - anchors.centerIn: parent + Row { + anchors.horizontalCenter: parent.horizontalCenter + + Text { + text: "Password?" + font.pixelSize: hifi.fonts.pixelSize * 0.8 + font.underline: true + color: "#e0e0e0" + width: loginDialog.inputHeight * 4 + horizontalAlignment: Text.AlignRight anchors.verticalCenter: parent.verticalCenter - spacing: 8 + + MouseArea { + anchors.fill: parent + cursorShape: "PointingHandCursor" + onClicked: { + loginDialog.openUrl(loginDialog.rootUrl + "/users/password/new") + } + } + } + + Item { + width: loginDialog.inputHeight + loginDialog.inputSpacing * 2 + height: loginDialog.inputHeight + Image { - id: loginIcon - height: 32 - width: 32 - source: "../images/login.svg" - } - Text { - text: "Login" - color: "white" - width: 64 - height: parent.height + id: hifiIcon + source: "../images/hifi-logo-blackish.svg" + width: loginDialog.inputHeight + height: width + anchors { + horizontalCenter: parent.horizontalCenter + verticalCenter: parent.verticalCenter + } } } - } + Text { + text: "Register" + font.pixelSize: hifi.fonts.pixelSize * 0.8 + font.underline: true + color: "#e0e0e0" + width: loginDialog.inputHeight * 4 + horizontalAlignment: Text.AlignLeft + anchors.verticalCenter: parent.verticalCenter - Text { - width: parent.width - height: 24 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - text:"Create Account" - font.pointSize: 12 - font.bold: true - color: hifi.colors.hifiBlue - - MouseArea { - anchors.fill: parent - onClicked: { - loginDialog.openUrl(loginDialog.rootUrl + "/signup") - } - } - } - - Text { - width: parent.width - height: 24 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.pointSize: 12 - text: "Recover Password" - color: hifi.colors.hifiBlue - - MouseArea { - anchors.fill: parent - onClicked: { - loginDialog.openUrl(loginDialog.rootUrl + "/users/password/new") + MouseArea { + anchors.fill: parent + cursorShape: "PointingHandCursor" + onClicked: { + loginDialog.openUrl(loginDialog.rootUrl + "/signup") + } } } } } } + + onOpacityChanged: { + // Set focus once animation is completed so that focus is set at start-up when not logged in + if (opacity == 1.0) { + username.forceActiveFocus() + } + } + + onVisibleChanged: { + if (!visible) { + username.text = "" + password.text = "" + loginDialog.statusText = "" + } + } + Keys.onPressed: { - switch(event.key) { + switch (event.key) { + case Qt.Key_Escape: + case Qt.Key_Back: + enabled = false + event.accepted = true + break case Qt.Key_Enter: case Qt.Key_Return: if (username.activeFocus) { @@ -192,7 +361,7 @@ Dialog { loginDialog.login(username.text, password.text) } } - break; + break } } } diff --git a/interface/resources/qml/MarketplaceDialog.qml b/interface/resources/qml/MarketplaceDialog.qml index 58bb3e6183..946f32e84a 100644 --- a/interface/resources/qml/MarketplaceDialog.qml +++ b/interface/resources/qml/MarketplaceDialog.qml @@ -5,7 +5,7 @@ import QtQuick.Controls.Styles 1.3 import QtWebKit 3.0 import "controls" -Dialog { +VrDialog { title: "Test Dlg" id: testDialog objectName: "Browser" diff --git a/interface/resources/qml/MessageDialog.qml b/interface/resources/qml/MessageDialog.qml index dd410b8070..e8b01df9d0 100644 --- a/interface/resources/qml/MessageDialog.qml +++ b/interface/resources/qml/MessageDialog.qml @@ -5,7 +5,7 @@ import QtQuick.Dialogs 1.2 import "controls" import "styles" -Dialog { +VrDialog { id: root HifiConstants { id: hifi } property real spacing: hifi.layout.spacing diff --git a/interface/resources/qml/TestDialog.qml b/interface/resources/qml/TestDialog.qml index 15bd790c22..e6675b7282 100644 --- a/interface/resources/qml/TestDialog.qml +++ b/interface/resources/qml/TestDialog.qml @@ -3,7 +3,7 @@ import QtQuick.Controls 1.2 import QtQuick.Controls.Styles 1.3 import "controls" -Dialog { +VrDialog { title: "Test Dialog" id: testDialog objectName: "TestDialog" diff --git a/interface/resources/qml/controls/DialogContainer.qml b/interface/resources/qml/controls/DialogContainer.qml new file mode 100644 index 0000000000..4aa4e45d67 --- /dev/null +++ b/interface/resources/qml/controls/DialogContainer.qml @@ -0,0 +1,65 @@ +// +// DialogCommon.qml +// +// Created by David Rowe on 3 Jun 2015 +// 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" + +Item { + id: root + + property bool destroyOnInvisible: true + + + // The UI enables an object, rather than manipulating its visibility, so that we can do animations in both directions. + // Because visibility and enabled are booleans, they cannot be animated. So when enabled is changed, we modify a property + // that can be animated, like scale or opacity, and then when the target animation value is reached, we can modify the + // visibility. + enabled: false + opacity: 0.0 + + onEnabledChanged: { + opacity = enabled ? 1.0 : 0.0 + } + + Behavior on opacity { + // Animate opacity. + NumberAnimation { + duration: hifi.effects.fadeInDuration + easing.type: Easing.OutCubic + } + } + + onOpacityChanged: { + // Once we're transparent, disable the dialog's visibility. + visible = (opacity != 0.0) + } + + onVisibleChanged: { + if (!visible) { + // Some dialogs should be destroyed when they become invisible. + if (destroyOnInvisible) { + destroy() + } + } + } + + + Keys.onPressed: { + switch(event.key) { + case Qt.Key_W: + if (event.modifiers == Qt.ControlModifier) { + enabled = false + event.accepted = true + } + break + } + } +} diff --git a/interface/resources/qml/controls/Dialog.qml b/interface/resources/qml/controls/VrDialog.qml similarity index 100% rename from interface/resources/qml/controls/Dialog.qml rename to interface/resources/qml/controls/VrDialog.qml diff --git a/interface/resources/qml/styles/HifiConstants.qml b/interface/resources/qml/styles/HifiConstants.qml index fa556f2083..c232b993d1 100644 --- a/interface/resources/qml/styles/HifiConstants.qml +++ b/interface/resources/qml/styles/HifiConstants.qml @@ -13,10 +13,9 @@ Item { readonly property color hifiBlue: "#0e7077" readonly property color window: sysPalette.window readonly property color dialogBackground: sysPalette.window - //readonly property color dialogBackground: "#00000000" readonly property color inputBackground: "white" readonly property color background: sysPalette.dark - readonly property color text: sysPalette.text + readonly property color text: "#202020" readonly property color disabledText: "gray" readonly property color hintText: "gray" // A bit darker than sysPalette.dark so that it is visible on the DK2 readonly property color light: sysPalette.light diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3ee470cc17..a957768d72 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -477,7 +477,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : addressManager->setPositionGetter(getPositionForPath); addressManager->setOrientationGetter(getOrientationForPath); - connect(addressManager.data(), &AddressManager::rootPlaceNameChanged, this, &Application::updateWindowTitle); + connect(addressManager.data(), &AddressManager::hostChanged, this, &Application::updateWindowTitle); connect(this, &QCoreApplication::aboutToQuit, addressManager.data(), &AddressManager::storeCurrentAddress); #ifdef _WIN32 @@ -3656,7 +3656,7 @@ void Application::updateWindowTitle(){ QString connectionStatus = nodeList->getDomainHandler().isConnected() ? "" : " (NOT CONNECTED) "; QString username = AccountManager::getInstance().getAccountInfo().getUsername(); - QString currentPlaceName = DependencyManager::get()->getRootPlaceName(); + QString currentPlaceName = DependencyManager::get()->getHost(); if (currentPlaceName.isEmpty()) { currentPlaceName = nodeList->getDomainHandler().getHostname(); diff --git a/interface/src/ui/LoginDialog.cpp b/interface/src/ui/LoginDialog.cpp index b452f153f0..196ba5d29e 100644 --- a/interface/src/ui/LoginDialog.cpp +++ b/interface/src/ui/LoginDialog.cpp @@ -1,6 +1,6 @@ // -// // LoginDialog.cpp +// interface/src/ui // // Created by Bradley Austin Davis on 2015/04/14 // Copyright 2015 High Fidelity, Inc. @@ -8,16 +8,22 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // + #include "LoginDialog.h" -#include "DependencyManager.h" -#include "AccountManager.h" -#include "Menu.h" +#include + #include +#include "AccountManager.h" +#include "DependencyManager.h" +#include "Menu.h" + HIFI_QML_DEF(LoginDialog) -LoginDialog::LoginDialog(QQuickItem *parent) : OffscreenQmlDialog(parent), _rootUrl(NetworkingConstants::METAVERSE_SERVER_URL.toString()) { +LoginDialog::LoginDialog(QQuickItem *parent) : OffscreenQmlDialog(parent), + _rootUrl(NetworkingConstants::METAVERSE_SERVER_URL.toString()) +{ connect(&AccountManager::getInstance(), &AccountManager::loginComplete, this, &LoginDialog::handleLoginCompleted); connect(&AccountManager::getInstance(), &AccountManager::loginFailed, @@ -48,7 +54,7 @@ void LoginDialog::handleLoginCompleted(const QUrl&) { } void LoginDialog::handleLoginFailed() { - setStatusText("Invalid username or password.< / font>"); + setStatusText("Invalid username or password"); } void LoginDialog::setStatusText(const QString& statusText) { @@ -68,10 +74,11 @@ QString LoginDialog::rootUrl() const { void LoginDialog::login(const QString& username, const QString& password) { qDebug() << "Attempting to login " << username; - setStatusText("Authenticating..."); + setStatusText("Logging in..."); AccountManager::getInstance().requestAccessToken(username, password); } void LoginDialog::openUrl(const QString& url) { qDebug() << url; + QDesktopServices::openUrl(url); } diff --git a/interface/src/ui/LoginDialog.h b/interface/src/ui/LoginDialog.h index e9ae0a1c16..50c820aa07 100644 --- a/interface/src/ui/LoginDialog.h +++ b/interface/src/ui/LoginDialog.h @@ -1,5 +1,6 @@ // // LoginDialog.h +// interface/src/ui // // Created by Bradley Austin Davis on 2015/04/14 // Copyright 2015 High Fidelity, Inc. @@ -9,6 +10,7 @@ // #pragma once + #ifndef hifi_LoginDialog_h #define hifi_LoginDialog_h diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp index 3c6b7bd3f5..a86ce78655 100644 --- a/libraries/networking/src/AddressManager.cpp +++ b/libraries/networking/src/AddressManager.cpp @@ -30,7 +30,7 @@ const QString SETTINGS_CURRENT_ADDRESS_KEY = "address"; Setting::Handle currentAddressHandle(QStringList() << ADDRESS_MANAGER_SETTINGS_GROUP << "address", DEFAULT_HIFI_ADDRESS); AddressManager::AddressManager() : - _rootPlaceName(), + _host(), _rootPlaceID(), _positionGetter(NULL), _orientationGetter(NULL) @@ -45,7 +45,7 @@ const QUrl AddressManager::currentAddress() const { QUrl hifiURL; hifiURL.setScheme(HIFI_URL_SCHEME); - hifiURL.setHost(_rootPlaceName); + hifiURL.setHost(_host); hifiURL.setPath(currentPath()); return hifiURL; @@ -123,6 +123,10 @@ bool AddressManager::handleUrl(const QUrl& lookupUrl) { + (lookupUrl.port() == -1 ? "" : ":" + QString::number(lookupUrl.port())))) { // we may have a path that defines a relative viewpoint - if so we should jump to that now handlePath(lookupUrl.path()); + } else if (handleDomainID(lookupUrl.host())){ + // no place name - this is probably a domain ID + // try to look up the domain ID on the metaverse API + attemptDomainIDLookup(lookupUrl.host(), lookupUrl.path()); } else { // wasn't an address - lookup the place name // we may have a path that defines a relative viewpoint - pass that through the lookup so we can go to it after @@ -161,11 +165,18 @@ void AddressManager::handleLookupString(const QString& lookupString) { } } +const QString DATA_OBJECT_DOMAIN_KEY = "domain"; + + void AddressManager::handleAPIResponse(QNetworkReply& requestReply) { QJsonObject responseObject = QJsonDocument::fromJson(requestReply.readAll()).object(); QJsonObject dataObject = responseObject["data"].toObject(); - goToAddressFromObject(dataObject.toVariantMap(), requestReply); + if (!dataObject.isEmpty()) { + goToAddressFromObject(dataObject.toVariantMap(), requestReply); + } else if (responseObject.contains(DATA_OBJECT_DOMAIN_KEY)) { + goToAddressFromObject(responseObject.toVariantMap(), requestReply); + } emit lookupResultsFinished(); } @@ -180,6 +191,8 @@ void AddressManager::goToAddressFromObject(const QVariantMap& dataObject, const QVariantMap locationMap; if (dataObject.contains(DATA_OBJECT_PLACE_KEY)) { locationMap = dataObject[DATA_OBJECT_PLACE_KEY].toMap(); + } else if (dataObject.contains(DATA_OBJECT_DOMAIN_KEY)) { + locationMap = dataObject; } else { locationMap = dataObject[DATA_OBJECT_USER_LOCATION_KEY].toMap(); } @@ -206,6 +219,10 @@ void AddressManager::goToAddressFromObject(const QVariantMap& dataObject, const DependencyManager::get()->flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::HandleAddress); + const QString DOMAIN_ID_KEY = "id"; + QString domainIDString = domainObject[DOMAIN_ID_KEY].toString(); + QUuid domainID(domainIDString); + if (domainObject.contains(DOMAIN_NETWORK_ADDRESS_KEY)) { QString domainHostname = domainObject[DOMAIN_NETWORK_ADDRESS_KEY].toString(); @@ -219,10 +236,6 @@ void AddressManager::goToAddressFromObject(const QVariantMap& dataObject, const } else { QString iceServerAddress = domainObject[DOMAIN_ICE_SERVER_ADDRESS_KEY].toString(); - const QString DOMAIN_ID_KEY = "id"; - QString domainIDString = domainObject[DOMAIN_ID_KEY].toString(); - QUuid domainID(domainIDString); - qCDebug(networking) << "Possible domain change required to connect to domain with ID" << domainID << "via ice-server at" << iceServerAddress; @@ -235,8 +248,12 @@ void AddressManager::goToAddressFromObject(const QVariantMap& dataObject, const // set our current root place name to the name that came back const QString PLACE_NAME_KEY = "name"; - QString newRootPlaceName = rootMap[PLACE_NAME_KEY].toString(); - setRootPlaceName(newRootPlaceName); + QString placeName = rootMap[PLACE_NAME_KEY].toString(); + if (!placeName.isEmpty()) { + setHost(placeName); + } else { + setHost(domainIDString); + } // check if we had a path to override the path returned QString overridePath = reply.property(OVERRIDE_PATH_KEY).toString(); @@ -304,6 +321,24 @@ void AddressManager::attemptPlaceNameLookup(const QString& lookupString, const Q QByteArray(), NULL, requestParams); } +const QString GET_DOMAIN_ID = "/api/v1/domains/%1"; + +void AddressManager::attemptDomainIDLookup(const QString& lookupString, const QString& overridePath) { + // assume this is a domain ID and see if we can get any info on it + QString domainID = QUrl::toPercentEncoding(lookupString); + + QVariantMap requestParams; + if (!overridePath.isEmpty()) { + requestParams.insert(OVERRIDE_PATH_KEY, overridePath); + } + + AccountManager::getInstance().sendRequest(GET_DOMAIN_ID.arg(domainID), + AccountManagerAuth::None, + QNetworkAccessManager::GetOperation, + apiCallbackParameters(), + QByteArray(), NULL, requestParams); +} + bool AddressManager::handleNetworkAddress(const QString& lookupString) { const QString IP_ADDRESS_REGEX_STRING = "^((?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}" "(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))(?::(\\d{1,5}))?$"; @@ -335,7 +370,7 @@ bool AddressManager::handleNetworkAddress(const QString& lookupString) { quint16 domainPort = DEFAULT_DOMAIN_SERVER_PORT; if (!hostnameRegex.cap(2).isEmpty()) { - domainPort = (qint16) hostnameRegex.cap(2).toInt(); + domainPort = (qint16)hostnameRegex.cap(2).toInt(); } emit lookupResultsFinished(); @@ -347,6 +382,14 @@ bool AddressManager::handleNetworkAddress(const QString& lookupString) { return false; } +bool AddressManager::handleDomainID(const QString& host) { + const QString UUID_REGEX_STRING = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"; + + QRegExp domainIDRegex(UUID_REGEX_STRING, Qt::CaseInsensitive); + + return (domainIDRegex.indexIn(host) != -1); +} + void AddressManager::handlePath(const QString& path) { if (!handleViewpoint(path)) { qCDebug(networking) << "User entered path could not be handled as a viewpoint - " << path << @@ -422,16 +465,16 @@ bool AddressManager::handleUsername(const QString& lookupString) { return false; } -void AddressManager::setRootPlaceName(const QString& rootPlaceName) { - if (rootPlaceName != _rootPlaceName) { - _rootPlaceName = rootPlaceName; - emit rootPlaceNameChanged(_rootPlaceName); +void AddressManager::setHost(const QString& host) { + if (host != _host) { + _host = host; + emit hostChanged(_host); } } void AddressManager::setDomainInfo(const QString& hostname, quint16 port) { - _rootPlaceName = hostname; + _host = hostname; _rootPlaceID = QUuid(); qCDebug(networking) << "Possible domain change required to connect to domain at" << hostname << "on" << port; diff --git a/libraries/networking/src/AddressManager.h b/libraries/networking/src/AddressManager.h index 5831d62603..2b587a9bd7 100644 --- a/libraries/networking/src/AddressManager.h +++ b/libraries/networking/src/AddressManager.h @@ -35,7 +35,7 @@ class AddressManager : public QObject, public Dependency { Q_PROPERTY(bool isConnected READ isConnected) Q_PROPERTY(QUrl href READ currentAddress) Q_PROPERTY(QString protocol READ getProtocol) - Q_PROPERTY(QString hostname READ getRootPlaceName) + Q_PROPERTY(QString hostname READ getHost) Q_PROPERTY(QString pathname READ currentPath) public: bool isConnected(); @@ -46,10 +46,11 @@ public: const QUuid& getRootPlaceID() const { return _rootPlaceID; } - const QString& getRootPlaceName() const { return _rootPlaceName; } - void setRootPlaceName(const QString& rootPlaceName); + const QString& getHost() const { return _host; } + void setHost(const QString& host); void attemptPlaceNameLookup(const QString& lookupString, const QString& overridePath = QString()); + void attemptDomainIDLookup(const QString& lookupString, const QString& overridePath = QString()); void setPositionGetter(PositionGetter positionGetter) { _positionGetter = positionGetter; } void setOrientationGetter(OrientationGetter orientationGetter) { _orientationGetter = orientationGetter; } @@ -78,7 +79,7 @@ signals: bool hasOrientationChange, const glm::quat& newOrientation, bool shouldFaceLocation); void pathChangeRequired(const QString& newPath); - void rootPlaceNameChanged(const QString& newRootPlaceName); + void hostChanged(const QString& newHost); protected: AddressManager(); private slots: @@ -95,8 +96,9 @@ private: void handlePath(const QString& path); bool handleViewpoint(const QString& viewpointString, bool shouldFace = false); bool handleUsername(const QString& lookupString); + bool handleDomainID(const QString& host); - QString _rootPlaceName; + QString _host; QUuid _rootPlaceID; PositionGetter _positionGetter; OrientationGetter _orientationGetter;