From 8c9c7248d4a00b3233becfa60c2934e25be9ccf7 Mon Sep 17 00:00:00 2001 From: Alexia Mandeville Date: Mon, 12 Mar 2018 12:52:12 -0700 Subject: [PATCH 001/499] Reorganize of menu action items as well as QML categories --- .../hifi/dialogs/AvatarPreferencesDialog.qml | 2 +- .../hifi/dialogs/GeneralPreferencesDialog.qml | 2 +- .../dialogs/GraphicsPreferencesDialog.qml | 2 +- .../qml/hifi/tablet/ControllerSettings.qml | 19 +- .../hifi/tablet/TabletGraphicsPreferences.qml | 2 +- interface/src/Menu.cpp | 367 +++++++++--------- interface/src/Menu.h | 10 +- interface/src/ui/PreferencesDialog.cpp | 122 +++--- 8 files changed, 268 insertions(+), 258 deletions(-) diff --git a/interface/resources/qml/hifi/dialogs/AvatarPreferencesDialog.qml b/interface/resources/qml/hifi/dialogs/AvatarPreferencesDialog.qml index 86f195612c..01b2690afb 100644 --- a/interface/resources/qml/hifi/dialogs/AvatarPreferencesDialog.qml +++ b/interface/resources/qml/hifi/dialogs/AvatarPreferencesDialog.qml @@ -7,7 +7,7 @@ PreferencesDialog { id: root objectName: "AvatarPreferencesDialog" title: "Avatar Settings" - showCategories: [ "Avatar Basics", "Avatar Tuning", "Avatar Camera" ] + showCategories: [ "Avatar Basics", "Avatar Tuning" ] property var settings: Settings { category: root.objectName property alias x: root.x diff --git a/interface/resources/qml/hifi/dialogs/GeneralPreferencesDialog.qml b/interface/resources/qml/hifi/dialogs/GeneralPreferencesDialog.qml index 6f5798e2b2..cb4913f999 100644 --- a/interface/resources/qml/hifi/dialogs/GeneralPreferencesDialog.qml +++ b/interface/resources/qml/hifi/dialogs/GeneralPreferencesDialog.qml @@ -17,7 +17,7 @@ PreferencesDialog { id: root objectName: "GeneralPreferencesDialog" title: "General Settings" - showCategories: ["UI", "Snapshots", "Privacy", "HMD", "Game Controller", "Sixense Controllers", "Perception Neuron", "Kinect", "Leap Motion"] + showCategories: ["User Interface", "HMD", "Snapshots", "Privacy"] property var settings: Settings { category: root.objectName property alias x: root.x diff --git a/interface/resources/qml/hifi/dialogs/GraphicsPreferencesDialog.qml b/interface/resources/qml/hifi/dialogs/GraphicsPreferencesDialog.qml index d95bafd0a9..1388889248 100644 --- a/interface/resources/qml/hifi/dialogs/GraphicsPreferencesDialog.qml +++ b/interface/resources/qml/hifi/dialogs/GraphicsPreferencesDialog.qml @@ -7,7 +7,7 @@ PreferencesDialog { id: root objectName: "GraphicsPreferencesDialog" title: "Graphics Settings" - showCategories: ["Graphics"] + showCategories: ["Graphics Quality"] property var settings: Settings { category: root.objectName property alias x: root.x diff --git a/interface/resources/qml/hifi/tablet/ControllerSettings.qml b/interface/resources/qml/hifi/tablet/ControllerSettings.qml index 4814eaf01c..b71719aa48 100644 --- a/interface/resources/qml/hifi/tablet/ControllerSettings.qml +++ b/interface/resources/qml/hifi/tablet/ControllerSettings.qml @@ -9,10 +9,26 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import QtGraphicalEffects 1.0 +import Qt.labs.settings 1.0 import "../../styles-uit" import "../../controls" import "../../controls-uit" as HifiControls +import "../../dialogs" +PreferencesDialog { + id: root + objectName: "ControlSettings" + title: "Control Settings" + showCategories: ["VR Movement", "Mouse Sensitivity", "Game Controller", "Face Tracking", "Sixense Controllers", "Perception Neuron", "Kinect", "Leap Motion"] + property var settings: Settings { + category: root.objectName + property alias x: root.x + property alias y: root.y + property alias width: root.width + property alias height: root.height + } +} +/* StackView { id: stack initialItem: inputConfiguration @@ -45,7 +61,7 @@ StackView { RalewayRegular { id: header - text: "Controller Settings" + text: "Control Settings" size: 22 color: "white" @@ -226,3 +242,4 @@ StackView { timer.start(); } } +*/ diff --git a/interface/resources/qml/hifi/tablet/TabletGraphicsPreferences.qml b/interface/resources/qml/hifi/tablet/TabletGraphicsPreferences.qml index 25b5be05f2..67794e8f14 100644 --- a/interface/resources/qml/hifi/tablet/TabletGraphicsPreferences.qml +++ b/interface/resources/qml/hifi/tablet/TabletGraphicsPreferences.qml @@ -32,6 +32,6 @@ StackView { TabletPreferencesDialog { id: root objectName: "TabletGraphicsPreferences" - showCategories: ["Graphics"] + showCategories: ["Graphics Quality"] } } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 8c0ac584c5..9e11ad801d 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include @@ -43,12 +45,13 @@ #include "ui/StandAloneJSConsole.h" #include "InterfaceLogging.h" #include "LocationBookmarks.h" +#include "Menu.h" #if defined(Q_OS_MAC) || defined(Q_OS_WIN) #include "SpeechRecognizer.h" #endif -#include "Menu.h" + extern bool DEV_DECIMATE_TEXTURES; @@ -76,9 +79,6 @@ Menu::Menu() { dialogsManager.data(), &DialogsManager::toggleLoginDialog); } - // File > Help - addActionToQMenuAndActionHash(fileMenu, MenuOption::Help, 0, qApp, SLOT(showHelp())); - // File > Quit addActionToQMenuAndActionHash(fileMenu, MenuOption::Quit, Qt::CTRL | Qt::Key_Q, qApp, SLOT(quit()), QAction::QuitRole); @@ -97,6 +97,22 @@ Menu::Menu() { redoAction->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_Z); addActionToQMenuAndActionHash(editMenu, redoAction); + editMenu->addSeparator(); + + // Edit > Cut + addActionToQMenuAndActionHash(editMenu, "Cut", Qt::CTRL | Qt::Key_X); + + // Edit > Copy + addActionToQMenuAndActionHash(editMenu, "Copy", Qt::CTRL | Qt::Key_C); + + // Edit > Paste + addActionToQMenuAndActionHash(editMenu, "Paste", Qt::CTRL | Qt::Key_V); + + // Edit > Delete + addActionToQMenuAndActionHash(editMenu, "Delete", Qt::Key_Delete); + + editMenu->addSeparator(); + // Edit > Running Scripts auto action = addActionToQMenuAndActionHash(editMenu, MenuOption::RunningScripts, Qt::CTRL | Qt::Key_J); connect(action, &QAction::triggered, [] { @@ -106,41 +122,9 @@ Menu::Menu() { qApp->showDialog(widgetUrl, tabletUrl, name); }); - // Edit > Open and Run Script from File... [advanced] - addActionToQMenuAndActionHash(editMenu, MenuOption::LoadScript, Qt::CTRL | Qt::Key_O, - qApp, SLOT(loadDialog()), - QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); - - // Edit > Open and Run Script from Url... [advanced] - addActionToQMenuAndActionHash(editMenu, MenuOption::LoadScriptURL, - Qt::CTRL | Qt::SHIFT | Qt::Key_O, qApp, SLOT(loadScriptURLDialog()), - QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); - - auto scriptEngines = DependencyManager::get(); - // Edit > Stop All Scripts... [advanced] - addActionToQMenuAndActionHash(editMenu, MenuOption::StopAllScripts, 0, - scriptEngines.data(), SLOT(stopAllScripts()), - QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); - - // Edit > Reload All Scripts... [advanced] - action = addActionToQMenuAndActionHash(editMenu, MenuOption::ReloadAllScripts, Qt::CTRL | Qt::Key_R, - nullptr, nullptr, - QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); - connect(action, &QAction::triggered, [] { - DependencyManager::get()->reloadAllScripts(); - DependencyManager::get()->clearCache(); - }); - - - // Edit > Console... [advanced] - addActionToQMenuAndActionHash(editMenu, MenuOption::Console, Qt::CTRL | Qt::ALT | Qt::Key_J, - DependencyManager::get().data(), - SLOT(toggleConsole()), - QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); - editMenu->addSeparator(); - // Edit > My Asset Server + // Edit > Asset Browser auto assetServerAction = addActionToQMenuAndActionHash(editMenu, MenuOption::AssetServer, Qt::CTRL | Qt::SHIFT | Qt::Key_A, qApp, SLOT(showAssetServerWidget())); @@ -148,64 +132,16 @@ Menu::Menu() { QObject::connect(nodeList.data(), &NodeList::canWriteAssetsChanged, assetServerAction, &QAction::setEnabled); assetServerAction->setEnabled(nodeList->getThisNodeCanWriteAssets()); - // Edit > Package Model... [advanced] + // Edit > Package Model as .fst... addActionToQMenuAndActionHash(editMenu, MenuOption::PackageModel, 0, - qApp, SLOT(packageModel()), - QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); + qApp, SLOT(packageModel())); - // Edit > Reload All Content [advanced] - addActionToQMenuAndActionHash(editMenu, MenuOption::ReloadContent, 0, qApp, SLOT(reloadResourceCaches()), - QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); + // Edit > Reload All Content + addActionToQMenuAndActionHash(editMenu, MenuOption::ReloadContent, 0, qApp, SLOT(reloadResourceCaches())); - // Avatar menu ---------------------------------- - MenuWrapper* avatarMenu = addMenu("Avatar"); auto avatarManager = DependencyManager::get(); auto avatar = avatarManager->getMyAvatar(); - // Avatar > Attachments... - action = addActionToQMenuAndActionHash(avatarMenu, MenuOption::Attachments); - connect(action, &QAction::triggered, [] { - qApp->showDialog(QString("hifi/dialogs/AttachmentsDialog.qml"), - QString("hifi/tablet/TabletAttachmentsDialog.qml"), "AttachmentsDialog"); - }); - - // Avatar > Size - MenuWrapper* avatarSizeMenu = avatarMenu->addMenu("Size"); - - // Avatar > Size > Increase - addActionToQMenuAndActionHash(avatarSizeMenu, - MenuOption::IncreaseAvatarSize, - 0, // QML Qt::Key_Plus, - avatar.get(), SLOT(increaseSize())); - - // Avatar > Size > Decrease - addActionToQMenuAndActionHash(avatarSizeMenu, - MenuOption::DecreaseAvatarSize, - 0, // QML Qt::Key_Minus, - avatar.get(), SLOT(decreaseSize())); - - // Avatar > Size > Reset - addActionToQMenuAndActionHash(avatarSizeMenu, - MenuOption::ResetAvatarSize, - 0, // QML Qt::Key_Equal, - avatar.get(), SLOT(resetSize())); - - // Avatar > Reset Sensors - addActionToQMenuAndActionHash(avatarMenu, - MenuOption::ResetSensors, - 0, // QML Qt::Key_Apostrophe, - qApp, SLOT(resetSensors())); - - addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::EnableAvatarCollisions, 0, true, - avatar.get(), SLOT(updateMotionBehaviorFromMenu())); - - addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::EnableFlying, 0, true, - avatar.get(), SLOT(setFlyingEnabled(bool))); - - // Avatar > AvatarBookmarks related menus -- Note: the AvatarBookmarks class adds its own submenus here. - auto avatarBookmarks = DependencyManager::get(); - avatarBookmarks->setupMenus(this, avatarMenu); - // Display menu ---------------------------------- // FIXME - this is not yet matching Alan's spec because it doesn't have // menus for "2D"/"3D" - we need to add support for detecting the appropriate @@ -225,38 +161,36 @@ Menu::Menu() { // View > First Person auto firstPersonAction = cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash( - viewMenu, MenuOption::FirstPerson, Qt::CTRL | Qt::Key_F, + viewMenu, MenuOption::FirstPerson, Qt::Key_1, true, qApp, SLOT(cameraMenuChanged()))); firstPersonAction->setProperty(EXCLUSION_GROUP_KEY, QVariant::fromValue(cameraModeGroup)); // View > Third Person auto thirdPersonAction = cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash( - viewMenu, MenuOption::ThirdPerson, Qt::CTRL | Qt::Key_G, + viewMenu, MenuOption::ThirdPerson, Qt::Key_3, false, qApp, SLOT(cameraMenuChanged()))); thirdPersonAction->setProperty(EXCLUSION_GROUP_KEY, QVariant::fromValue(cameraModeGroup)); // View > Mirror auto viewMirrorAction = cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash( - viewMenu, MenuOption::FullscreenMirror, Qt::CTRL | Qt::Key_H, + viewMenu, MenuOption::FullscreenMirror, Qt::Key_2, false, qApp, SLOT(cameraMenuChanged()))); viewMirrorAction->setProperty(EXCLUSION_GROUP_KEY, QVariant::fromValue(cameraModeGroup)); - // View > Independent [advanced] + // View > Independent auto viewIndependentAction = cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::IndependentMode, 0, - false, qApp, SLOT(cameraMenuChanged()), - UNSPECIFIED_POSITION, "Advanced")); + false, qApp, SLOT(cameraMenuChanged()))); viewIndependentAction->setProperty(EXCLUSION_GROUP_KEY, QVariant::fromValue(cameraModeGroup)); - // View > Entity Camera [advanced] + // View > Entity Camera auto viewEntityCameraAction = cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::CameraEntityMode, 0, - false, qApp, SLOT(cameraMenuChanged()), - UNSPECIFIED_POSITION, "Advanced")); + false, qApp, SLOT(cameraMenuChanged()))); viewEntityCameraAction->setProperty(EXCLUSION_GROUP_KEY, QVariant::fromValue(cameraModeGroup)); @@ -264,54 +198,51 @@ Menu::Menu() { // View > Center Player In View addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::CenterPlayerInView, - 0, true, qApp, SLOT(rotationModeChanged()), - UNSPECIFIED_POSITION, "Advanced"); + 0, true, qApp, SLOT(rotationModeChanged())); + //TODO: remove Overlays action, but the action is tied to some other places in code // View > Overlays addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Overlays, 0, true); // View > Enter First Person Mode in HMD addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPersonHMD, 0, true); + //TODO: Remove Navigation menu when these functions are included in GoTo menu // Navigate menu ---------------------------------- MenuWrapper* navigateMenu = addMenu("Navigate"); - // Navigate > Show Address Bar - addActionToQMenuAndActionHash(navigateMenu, MenuOption::AddressBar, Qt::CTRL | Qt::Key_L, - dialogsManager.data(), SLOT(toggleAddressBar())); - // Navigate > LocationBookmarks related menus -- Note: the LocationBookmarks class adds its own submenus here. auto locationBookmarks = DependencyManager::get(); locationBookmarks->setupMenus(this, navigateMenu); - // Navigate > Copy Address [advanced] + // Navigate > Copy Address auto addressManager = DependencyManager::get(); addActionToQMenuAndActionHash(navigateMenu, MenuOption::CopyAddress, 0, - addressManager.data(), SLOT(copyAddress()), - QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); + addressManager.data(), SLOT(copyAddress())); - // Navigate > Copy Path [advanced] + // Navigate > Copy Path addActionToQMenuAndActionHash(navigateMenu, MenuOption::CopyPath, 0, - addressManager.data(), SLOT(copyPath()), - QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); + addressManager.data(), SLOT(copyPath())); // Settings menu ---------------------------------- MenuWrapper* settingsMenu = addMenu("Settings"); - // Settings > Advance Menus - addCheckableActionToQMenuAndActionHash(settingsMenu, "Advanced Menus", 0, false, this, SLOT(toggleAdvancedMenus())); - - // Settings > Developer Menus - addCheckableActionToQMenuAndActionHash(settingsMenu, "Developer Menus", 0, false, this, SLOT(toggleDeveloperMenus())); - // Settings > General... - action = addActionToQMenuAndActionHash(settingsMenu, MenuOption::Preferences, Qt::CTRL | Qt::Key_Comma, nullptr, nullptr, QAction::PreferencesRole); + action = addActionToQMenuAndActionHash(settingsMenu, MenuOption::Preferences, Qt::CTRL | Qt::Key_G, nullptr, nullptr, QAction::PreferencesRole); connect(action, &QAction::triggered, [] { qApp->showDialog(QString("hifi/dialogs/GeneralPreferencesDialog.qml"), QString("hifi/tablet/TabletGeneralPreferences.qml"), "GeneralPreferencesDialog"); }); + // Settings > Controls... + action = addActionToQMenuAndActionHash(settingsMenu, "Controls..."); + connect(action, &QAction::triggered, [] { + qApp->showDialog(QString("hifi/tablet/ControllerSettings.qml"), + QString("hifi/tablet/ControllerSettings.qml"), "ControlSettings"); + }); + + // Settings > Audio... action = addActionToQMenuAndActionHash(settingsMenu, "Audio..."); connect(action, &QAction::triggered, [] { static const QUrl widgetUrl("hifi/dialogs/Audio.qml"); @@ -320,6 +251,13 @@ Menu::Menu() { qApp->showDialog(widgetUrl, tabletUrl, name); }); + // Settings > Graphics... + action = addActionToQMenuAndActionHash(settingsMenu, "Graphics..."); + connect(action, &QAction::triggered, [] { + qApp->showDialog(QString("hifi/dialogs/GraphicsPreferencesDialog.qml"), + QString("hifi/tablet/TabletGraphicsPreferences.qml"), "GraphicsPreferencesDialog"); + }); + // Settings > Avatar... action = addActionToQMenuAndActionHash(settingsMenu, "Avatar..."); connect(action, &QAction::triggered, [] { @@ -327,44 +265,83 @@ Menu::Menu() { QString("hifi/tablet/TabletAvatarPreferences.qml"), "AvatarPreferencesDialog"); }); - // Settings > LOD... - action = addActionToQMenuAndActionHash(settingsMenu, "LOD..."); - connect(action, &QAction::triggered, [] { - qApp->showDialog(QString("hifi/dialogs/LodPreferencesDialog.qml"), - QString("hifi/tablet/TabletLodPreferences.qml"), "LodPreferencesDialog"); - }); + // Settings > Notifications + MenuWrapper * notificationsMenu = settingsMenu->addMenu("Notifications"); //This was in notifications.js. The menu needs to be moved here. - action = addActionToQMenuAndActionHash(settingsMenu, "Controller Settings..."); - connect(action, &QAction::triggered, [] { - auto tablet = DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system"); - auto hmd = DependencyManager::get(); - tablet->loadQMLSource("hifi/tablet/ControllerSettings.qml"); + //TODO: Hookup notification actions below. + // Settings > Notifications > Play Notification Sounds + addActionToQMenuAndActionHash(notificationsMenu, "Play Notification Sounds"); - if (!hmd->getShouldShowTablet()) { - hmd->toggleShouldShowTablet(); - } - }); + notificationsMenu->addSeparator(); - // Settings > Control with Speech [advanced] -#if defined(Q_OS_MAC) || defined(Q_OS_WIN) - auto speechRecognizer = DependencyManager::get(); - QAction* speechRecognizerAction = addCheckableActionToQMenuAndActionHash(settingsMenu, MenuOption::ControlWithSpeech, - Qt::CTRL | Qt::SHIFT | Qt::Key_C, - speechRecognizer->getEnabled(), - speechRecognizer.data(), - SLOT(setEnabled(bool)), - UNSPECIFIED_POSITION, "Advanced"); - connect(speechRecognizer.data(), SIGNAL(enabledUpdated(bool)), speechRecognizerAction, SLOT(setChecked(bool))); -#endif + // Settings > Notifications > Play Sounds for: + addDisabledActionAndSeparator(notificationsMenu, "Show notifications for:"); + + // Settings > Notifications > Snapshot + addActionToQMenuAndActionHash(notificationsMenu, "Snapshot"); + + // Settings > Notifications > Level of Detail + addActionToQMenuAndActionHash(notificationsMenu, "Level of Detail"); + + // Settings > Notifications > Connection + addActionToQMenuAndActionHash(notificationsMenu, "Connection"); + + // Settings > Notifications > Connection Refused + addActionToQMenuAndActionHash(notificationsMenu, "Connection Refused"); + + // Settings > Notifications > Edit Error + addActionToQMenuAndActionHash(notificationsMenu, "Edit Error"); + + // Settings > Notifications > Tablet + addActionToQMenuAndActionHash(notificationsMenu, "Tablet"); + + // Settings > Notifications > Wallet + addActionToQMenuAndActionHash(notificationsMenu, "Wallet"); + + // Settings > Developer Menu + addCheckableActionToQMenuAndActionHash(settingsMenu, "Developer Menu", 0, false, this, SLOT(toggleDeveloperMenus())); + + // Settings > Ask to Reset Settings + addCheckableActionToQMenuAndActionHash(settingsMenu, MenuOption::AskToResetSettings, 0, false); // Developer menu ---------------------------------- MenuWrapper* developerMenu = addMenu("Developer", "Developer"); - // Developer > Graphics... - action = addActionToQMenuAndActionHash(developerMenu, "Graphics..."); + // Developer > Console... + addActionToQMenuAndActionHash(developerMenu, MenuOption::Console, Qt::CTRL | Qt::ALT | Qt::Key_J, + DependencyManager::get().data(), + SLOT(toggleConsole()), + QAction::NoRole); + + // Developer > Scripting >>> + MenuWrapper* scriptingOptionsMenu = developerMenu->addMenu("Scripting"); + + // Developer > Scripting > Log... + addActionToQMenuAndActionHash(scriptingOptionsMenu, MenuOption::Log, Qt::CTRL | Qt::SHIFT | Qt::Key_L, + qApp, SLOT(toggleLogDialog())); + + // Developer > Scripting > Entity Script Server Log + auto essLogAction = addActionToQMenuAndActionHash(scriptingOptionsMenu, MenuOption::EntityScriptServerLog, 0, + qApp, SLOT(toggleEntityScriptServerLogDialog())); + + QObject::connect(nodeList.data(), &NodeList::canRezChanged, essLogAction, [essLogAction] { + auto nodeList = DependencyManager::get(); + essLogAction->setEnabled(nodeList->getThisNodeCanRez()); + }); + + essLogAction->setEnabled(nodeList->getThisNodeCanRez()); + + // Developer > Scripting > Script Log (HMD Friendly)... + action = addActionToQMenuAndActionHash(scriptingOptionsMenu, "Script Log (HMD Friendly)...", Qt::NoButton, + qApp, SLOT(showScriptLogs())); + + // Developer > Scripting > API Debugger + action = addActionToQMenuAndActionHash(scriptingOptionsMenu, "API Debugger..."); connect(action, &QAction::triggered, [] { - qApp->showDialog(QString("hifi/dialogs/GraphicsPreferencesDialog.qml"), - QString("hifi/tablet/TabletGraphicsPreferences.qml"), "GraphicsPreferencesDialog"); + auto scriptEngines = DependencyManager::get(); + QUrl defaultScriptsLoc = PathUtils::defaultScriptsLocation(); + defaultScriptsLoc.setPath(defaultScriptsLoc.path() + "developer/utilities/tools/currentAPI.js"); + scriptEngines->loadScript(defaultScriptsLoc.toString()); }); // Developer > UI >>> @@ -698,12 +675,6 @@ Menu::Menu() { } addCheckableActionToQMenuAndActionHash(physicsOptionsMenu, MenuOption::PhysicsShowHulls, 0, false, qApp->getEntities().data(), SIGNAL(setRenderDebugHulls())); - // Developer > Ask to Reset Settings - addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::AskToResetSettings, 0, false); - - // Developer > Display Crash Options - addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::DisplayCrashOptions, 0, true); - // Developer > Crash >>> MenuWrapper* crashMenu = developerMenu->addMenu("Crash"); @@ -740,38 +711,23 @@ Menu::Menu() { action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashNewFaultThreaded); connect(action, &QAction::triggered, qApp, []() { std::thread([]() { crash::newFault(); }); }); - // Developer > Log... - addActionToQMenuAndActionHash(developerMenu, MenuOption::Log, Qt::CTRL | Qt::SHIFT | Qt::Key_L, - qApp, SLOT(toggleLogDialog())); - auto essLogAction = addActionToQMenuAndActionHash(developerMenu, MenuOption::EntityScriptServerLog, 0, - qApp, SLOT(toggleEntityScriptServerLogDialog())); - QObject::connect(nodeList.data(), &NodeList::canRezChanged, essLogAction, [essLogAction] { - auto nodeList = DependencyManager::get(); - essLogAction->setEnabled(nodeList->getThisNodeCanRez()); - }); - essLogAction->setEnabled(nodeList->getThisNodeCanRez()); - - action = addActionToQMenuAndActionHash(developerMenu, "Script Log (HMD friendly)...", Qt::NoButton, - qApp, SLOT(showScriptLogs())); + // Developer > Display Crash Options + addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::DisplayCrashOptions, 0, true); // Developer > Stats addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::Stats); - // Developer > Advanced Settings... - action = addActionToQMenuAndActionHash(developerMenu, "Advanced Preferences..."); - connect(action, &QAction::triggered, [] { - qApp->showDialog(QString("hifi/dialogs/AdvancedPreferencesDialog.qml"), - QString("hifi/tablet/AdvancedPreferencesDialog.qml"), "AdvancedPreferencesDialog"); - }); - - // Developer > API Debugger - action = addActionToQMenuAndActionHash(developerMenu, "API Debugger"); - connect(action, &QAction::triggered, [] { - auto scriptEngines = DependencyManager::get(); - QUrl defaultScriptsLoc = PathUtils::defaultScriptsLocation(); - defaultScriptsLoc.setPath(defaultScriptsLoc.path() + "developer/utilities/tools/currentAPI.js"); - scriptEngines->loadScript(defaultScriptsLoc.toString()); - }); + // Settings > Enable Speech Control API +#if defined(Q_OS_MAC) || defined(Q_OS_WIN) + auto speechRecognizer = DependencyManager::get(); + QAction* speechRecognizerAction = addCheckableActionToQMenuAndActionHash(settingsMenu, MenuOption::ControlWithSpeech, + Qt::CTRL | Qt::SHIFT | Qt::Key_C, + speechRecognizer->getEnabled(), + speechRecognizer.data(), + SLOT(setEnabled(bool)), + UNSPECIFIED_POSITION, "Advanced"); + connect(speechRecognizer.data(), SIGNAL(enabledUpdated(bool)), speechRecognizerAction, SLOT(setChecked(bool))); +#endif #if 0 /// -------------- REMOVED FOR NOW -------------- addDisabledActionAndSeparator(navigateMenu, "History"); @@ -798,6 +754,55 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::NamesAboveHeads, 0, true, NULL, NULL, UNSPECIFIED_POSITION, "Advanced"); #endif + + // Help/Application menu ---------------------------------- + MenuWrapper * helpMenu = addMenu("Help"); + + // Help > About High Fidelity + //TODO: Add dialog to show about: Logo, Company, Version + addActionToQMenuAndActionHash(helpMenu, "About High Fidelity"); + + helpMenu->addSeparator(); + + // Help > HiFi Docs + action = addActionToQMenuAndActionHash(helpMenu, "Online Documentation"); + connect(action, &QAction::triggered, qApp, [] { + QDesktopServices::openUrl(QUrl("https://docs.highfidelity.com/")); + }); + + // Help > HiFi Forum + action = addActionToQMenuAndActionHash(helpMenu, "Online Forums"); + connect(action, &QAction::triggered, qApp, [] { + QDesktopServices::openUrl(QUrl("https://forums.highfidelity.com/")); + }); + + // Help > Scripting Reference + action = addActionToQMenuAndActionHash(helpMenu, "Online Script Reference"); + connect(action, &QAction::triggered, qApp, [] { + QDesktopServices::openUrl(QUrl("https://docs.highfidelity.com/api-reference")); + }); + + addActionToQMenuAndActionHash(helpMenu, "Controls Reference", 0, qApp, SLOT(showHelp())); + + helpMenu->addSeparator(); + + // Help > Check for Updates + //ToDo: Add check for updates + addActionToQMenuAndActionHash(helpMenu, "Check for Updates"); + + helpMenu->addSeparator(); + + // Help > Release Notes + action = addActionToQMenuAndActionHash(helpMenu, "Release Notes"); + connect(action, &QAction::triggered, qApp, [] { + QDesktopServices::openUrl(QUrl("http://steamcommunity.com/games/390540/announcements/")); + }); + + // Help > Report a Bug! + action = addActionToQMenuAndActionHash(helpMenu, "Report a Bug!"); + connect(action, &QAction::triggered, qApp, [] { + QDesktopServices::openUrl(QUrl("mailto:support@highfidelity.com")); + }); } void Menu::addMenuItem(const MenuItemProperties& properties) { diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 34588535ec..5adde90b0f 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -32,7 +32,7 @@ namespace MenuOption { const QString AnimDebugDrawAnimPose = "Debug Draw Animation"; const QString AnimDebugDrawDefaultPose = "Debug Draw Default Pose"; const QString AnimDebugDrawPosition= "Debug Draw Position"; - const QString AskToResetSettings = "Ask To Reset Settings"; + const QString AskToResetSettings = "Ask To Reset Settings on Start"; const QString AssetMigration = "ATP Asset Migration"; const QString AssetServer = "Asset Browser"; const QString Attachments = "Attachments..."; @@ -59,7 +59,7 @@ namespace MenuOption { const QString Collisions = "Collisions"; const QString Connexion = "Activate 3D Connexion Devices"; const QString Console = "Console..."; - const QString ControlWithSpeech = "Control With Speech"; + const QString ControlWithSpeech = "Enable Speech Control API"; const QString CopyAddress = "Copy Address to Clipboard"; const QString CopyPath = "Copy Path to Clipboard"; const QString CoupleEyelids = "Couple Eyelids"; @@ -121,7 +121,7 @@ namespace MenuOption { const QString LoadScript = "Open and Run Script File..."; const QString LoadScriptURL = "Open and Run Script from URL..."; const QString LodTools = "LOD Tools"; - const QString Login = "Login / Sign Up"; + const QString Login = "Login/Sign Up"; const QString Log = "Log"; const QString LogExtraTimings = "Log Extra Timing Details"; const QString LowVelocityFilter = "Low Velocity Filter"; @@ -137,7 +137,7 @@ namespace MenuOption { const QString OpenVrThreadedSubmit = "OpenVR Threaded Submit"; const QString OutputMenu = "Display"; const QString Overlays = "Overlays"; - const QString PackageModel = "Package Model..."; + const QString PackageModel = "Package Model as .fst..."; const QString Pair = "Pair"; const QString PhysicsShowHulls = "Draw Collision Shapes"; const QString PhysicsShowOwned = "Highlight Simulation Ownership"; @@ -186,7 +186,7 @@ namespace MenuOption { const QString SimulateEyeTracking = "Simulate"; const QString SMIEyeTracking = "SMI Eye Tracking"; const QString SparseTextureManagement = "Enable Sparse Texture Management"; - const QString Stats = "Stats"; + const QString Stats = "Show Statistics"; const QString StopAllScripts = "Stop All Scripts"; const QString SuppressShortTimings = "Suppress Timings Less than 10ms"; const QString ThirdPerson = "Third Person"; diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 48b56c7ced..8860f4dab7 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -56,33 +56,31 @@ void setupPreferences() { preferences->addPreference(preference); } - { - auto getter = [=]()->bool { return myAvatar->getSnapTurn(); }; - auto setter = [=](bool value) { myAvatar->setSnapTurn(value); }; - preferences->addPreference(new CheckPreference(AVATAR_BASICS, "Snap turn when in HMD", getter, setter)); - } - { - auto getter = [=]()->bool { return myAvatar->getClearOverlayWhenMoving(); }; - auto setter = [=](bool value) { myAvatar->setClearOverlayWhenMoving(value); }; - preferences->addPreference(new CheckPreference(AVATAR_BASICS, "Clear overlays when moving", getter, setter)); - } - // UI - static const QString UI_CATEGORY { "UI" }; + static const QString UI_CATEGORY { "User Interface" }; { auto getter = []()->bool { return qApp->getSettingConstrainToolbarPosition(); }; auto setter = [](bool value) { qApp->setSettingConstrainToolbarPosition(value); }; preferences->addPreference(new CheckPreference(UI_CATEGORY, "Constrain Toolbar Position to Horizontal Center", getter, setter)); } + { - auto getter = []()->float { return qApp->getHMDTabletScale(); }; - auto setter = [](float value) { qApp->setHMDTabletScale(value); }; - auto preference = new SpinnerPreference(UI_CATEGORY, "HMD Tablet Scale %", getter, setter); + auto getter = []()->float { return qApp->getDesktopTabletScale(); }; + auto setter = [](float value) { qApp->setDesktopTabletScale(value); }; + auto preference = new SpinnerPreference(UI_CATEGORY, "Desktop Tablet Scale %", getter, setter); preference->setMin(20); preference->setMax(500); preferences->addPreference(preference); } + { + auto getter = []()->float { return qApp->getHMDTabletScale(); }; + auto setter = [](float value) { qApp->setHMDTabletScale(value); }; + auto preference = new SpinnerPreference(UI_CATEGORY, "VR Tablet Scale %", getter, setter); + preference->setMin(20); + preference->setMax(500); + preferences->addPreference(preference); + } { auto getter = []()->bool { return qApp->getPreferStylusOverLaser(); }; @@ -90,19 +88,18 @@ void setupPreferences() { preferences->addPreference(new CheckPreference(UI_CATEGORY, "Prefer Stylus Over Laser", getter, setter)); } - static const QString ADVANCED_UI_CATEGORY { "Advanced UI" }; { - auto getter = []()->float { return qApp->getDesktopTabletScale(); }; - auto setter = [](float value) { qApp->setDesktopTabletScale(value); }; - auto preference = new SpinnerPreference(ADVANCED_UI_CATEGORY, "Desktop Tablet Scale %", getter, setter); - preference->setMin(20); - preference->setMax(500); - preferences->addPreference(preference); + static const QString RETICLE_ICON_NAME = { Cursor::Manager::getIconName(Cursor::Icon::RETICLE) }; + auto getter = []()->bool { return qApp->getPreferredCursor() == RETICLE_ICON_NAME; }; + auto setter = [](bool value) { qApp->setPreferredCursor(value ? RETICLE_ICON_NAME : QString()); }; + preferences->addPreference(new CheckPreference(UI_CATEGORY, "Use reticle cursor instead of arrow", getter, setter)); } + + static const QString VIEW_CATEGORY{ "View" }; { auto getter = [=]()->float { return myAvatar->getRealWorldFieldOfView(); }; auto setter = [=](float value) { myAvatar->setRealWorldFieldOfView(value); }; - auto preference = new SpinnerPreference(ADVANCED_UI_CATEGORY, "Real world vertical field of view (angular size of monitor)", getter, setter); + auto preference = new SpinnerPreference(VIEW_CATEGORY, "Real world vertical field of view (angular size of monitor)", getter, setter); preference->setMin(1); preference->setMax(180); preferences->addPreference(preference); @@ -110,7 +107,7 @@ void setupPreferences() { { auto getter = []()->float { return qApp->getFieldOfView(); }; auto setter = [](float value) { qApp->setFieldOfView(value); }; - auto preference = new SpinnerPreference(ADVANCED_UI_CATEGORY, "Vertical field of view", getter, setter); + auto preference = new SpinnerPreference(VIEW_CATEGORY, "Vertical field of view", getter, setter); preference->setMin(1); preference->setMax(180); preference->setStep(1); @@ -126,12 +123,6 @@ void setupPreferences() { preferences->addPreference(new CheckPreference(UI_CATEGORY, "Prefer Avatar Finger Over Stylus", getter, setter)); } */ - { - static const QString RETICLE_ICON_NAME = { Cursor::Manager::getIconName(Cursor::Icon::RETICLE) }; - auto getter = []()->bool { return qApp->getPreferredCursor() == RETICLE_ICON_NAME; }; - auto setter = [](bool value) { qApp->setPreferredCursor(value ? RETICLE_ICON_NAME : QString()); }; - preferences->addPreference(new CheckPreference(UI_CATEGORY, "Use reticle cursor instead of arrow", getter, setter)); - } // Snapshots static const QString SNAPSHOTS { "Snapshots" }; @@ -160,27 +151,6 @@ void setupPreferences() { "this information you are helping to improve the product. ", getter, setter)); } - static const QString LOD_TUNING("Level of Detail Tuning"); - { - auto getter = []()->float { return DependencyManager::get()->getDesktopLODDecreaseFPS(); }; - auto setter = [](float value) { DependencyManager::get()->setDesktopLODDecreaseFPS(value); }; - auto preference = new SpinnerPreference(LOD_TUNING, "Minimum desktop FPS", getter, setter); - preference->setMin(0); - preference->setMax(120); - preference->setStep(1); - preferences->addPreference(preference); - } - - { - auto getter = []()->float { return DependencyManager::get()->getHMDLODDecreaseFPS(); }; - auto setter = [](float value) { DependencyManager::get()->setHMDLODDecreaseFPS(value); }; - auto preference = new SpinnerPreference(LOD_TUNING, "Minimum HMD FPS", getter, setter); - preference->setMin(0); - preference->setMax(120); - preference->setStep(1); - preferences->addPreference(preference); - } - static const QString AVATAR_TUNING { "Avatar Tuning" }; { auto getter = [=]()->QString { return myAvatar->getDominantHand(); }; @@ -210,16 +180,7 @@ void setupPreferences() { preference->setStep(0.001f); preferences->addPreference(preference); } - { - auto getter = []()->float { return DependencyManager::get()->getEyeClosingThreshold(); }; - auto setter = [](float value) { DependencyManager::get()->setEyeClosingThreshold(value); }; - preferences->addPreference(new SliderPreference(AVATAR_TUNING, "Camera binary eyelid threshold", getter, setter)); - } - { - auto getter = []()->float { return FaceTracker::getEyeDeflection(); }; - auto setter = [](float value) { FaceTracker::setEyeDeflection(value); }; - preferences->addPreference(new SliderPreference(AVATAR_TUNING, "Face tracker eye deflection", getter, setter)); - } + { auto getter = [=]()->QString { return myAvatar->getAnimGraphOverrideUrl().toString(); }; auto setter = [=](const QString& value) { myAvatar->setAnimGraphOverrideUrl(QUrl(value)); }; @@ -228,11 +189,38 @@ void setupPreferences() { preferences->addPreference(preference); } - static const QString AVATAR_CAMERA { "Avatar Camera" }; + static const QString FACE_TRACKING{ "Face Tracking" }; + { + auto getter = []()->float { return DependencyManager::get()->getEyeClosingThreshold(); }; + auto setter = [](float value) { DependencyManager::get()->setEyeClosingThreshold(value); }; + preferences->addPreference(new SliderPreference(FACE_TRACKING, "Eye Closing Threshold", getter, setter)); + } + { + auto getter = []()->float { return FaceTracker::getEyeDeflection(); }; + auto setter = [](float value) { FaceTracker::setEyeDeflection(value); }; + preferences->addPreference(new SliderPreference(FACE_TRACKING, "Eye Deflection", getter, setter)); + } + + static const QString MOVEMENT{ "VR Movement" }; + + { + auto getter = [=]()->bool { return myAvatar->getSnapTurn(); }; + auto setter = [=](bool value) { myAvatar->setSnapTurn(value); }; + preferences->addPreference(new CheckPreference(MOVEMENT, "Snap turn rotation", getter, setter)); + } + + //TODO: Update with advanced movement logic, test that it works + { + auto getter = [=]()->bool { return myAvatar->useAdvancedMovementControls(); }; + auto setter = [=](bool value) { myAvatar->setUseAdvancedMovementControls(value); }; + preferences->addPreference(new CheckPreference(MOVEMENT, "Advanced movement for hand controllers", getter, setter)); + } + + static const QString AVATAR_CAMERA{ "Mouse Sensitivity" }; { auto getter = [=]()->float { return myAvatar->getPitchSpeed(); }; auto setter = [=](float value) { myAvatar->setPitchSpeed(value); }; - auto preference = new SpinnerPreference(AVATAR_CAMERA, "Camera pitch speed (degrees/second)", getter, setter); + auto preference = new SpinnerPreference(AVATAR_CAMERA, "Pitch speed (degrees/second)", getter, setter); preference->setMin(1.0f); preference->setMax(360.0f); preferences->addPreference(preference); @@ -240,7 +228,7 @@ void setupPreferences() { { auto getter = [=]()->float { return myAvatar->getYawSpeed(); }; auto setter = [=](float value) { myAvatar->setYawSpeed(value); }; - auto preference = new SpinnerPreference(AVATAR_CAMERA, "Camera yaw speed (degrees/second)", getter, setter); + auto preference = new SpinnerPreference(AVATAR_CAMERA, "Yaw speed (degrees/second)", getter, setter); preference->setMin(1.0f); preference->setMax(360.0f); preferences->addPreference(preference); @@ -297,14 +285,14 @@ void setupPreferences() { { - static const QString RENDER("Graphics"); + static const QString GRAPHICS_QUALITY("Graphics Quality"); auto renderConfig = qApp->getRenderEngine()->getConfiguration(); if (renderConfig) { auto mainViewAmbientOcclusionConfig = renderConfig->getConfig("RenderMainView.AmbientOcclusion"); if (mainViewAmbientOcclusionConfig) { auto getter = [mainViewAmbientOcclusionConfig]()->QString { return mainViewAmbientOcclusionConfig->getPreset(); }; auto setter = [mainViewAmbientOcclusionConfig](QString preset) { mainViewAmbientOcclusionConfig->setPreset(preset); }; - auto preference = new ComboBoxPreference(RENDER, "Ambient occlusion", getter, setter); + auto preference = new ComboBoxPreference(GRAPHICS_QUALITY, "Ambient occlusion", getter, setter); preference->setItems(mainViewAmbientOcclusionConfig->getPresetList()); preferences->addPreference(preference); } @@ -313,7 +301,7 @@ void setupPreferences() { if (mainViewShadowConfig) { auto getter = [mainViewShadowConfig]()->QString { return mainViewShadowConfig->getPreset(); }; auto setter = [mainViewShadowConfig](QString preset) { mainViewShadowConfig->setPreset(preset); }; - auto preference = new ComboBoxPreference(RENDER, "Shadows", getter, setter); + auto preference = new ComboBoxPreference(GRAPHICS_QUALITY, "Shadows", getter, setter); preference->setItems(mainViewShadowConfig->getPresetList()); preferences->addPreference(preference); } From 61e2814db4dc0455e56aef4acc30cf5861f6cf92 Mon Sep 17 00:00:00 2001 From: Alexia Mandeville Date: Mon, 12 Mar 2018 13:07:21 -0700 Subject: [PATCH 002/499] Removing toolbar apps that are no longer necessary --- scripts/defaultScripts.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/scripts/defaultScripts.js b/scripts/defaultScripts.js index 71755e3abb..b0cbf0e246 100644 --- a/scripts/defaultScripts.js +++ b/scripts/defaultScripts.js @@ -19,14 +19,12 @@ var DEFAULT_SCRIPTS_COMBINED = [ "system/menu.js", "system/bubble.js", "system/snapshot.js", - "system/help.js", "system/pal.js", // "system/mod.js", // older UX, if you prefer "system/makeUserConnection.js", "system/tablet-goto.js", "system/marketplaces/marketplaces.js", "system/commerce/wallet.js", "system/edit.js", - "system/notifications.js", "system/dialTone.js", "system/firstPersonHMD.js", "system/tablet-ui/tabletUI.js", From c760c44531e1915671b17be1219301cfb0bcc045 Mon Sep 17 00:00:00 2001 From: Alexia Mandeville Date: Mon, 12 Mar 2018 13:17:23 -0700 Subject: [PATCH 003/499] Revert "Update repo script with marketplace script" This reverts commit 5139f3f50328c0299801906ba435d5e1528c72f8. --- scripts/tutorials/entity_scripts/sit.js | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/scripts/tutorials/entity_scripts/sit.js b/scripts/tutorials/entity_scripts/sit.js index 9de65d7037..70456ea493 100644 --- a/scripts/tutorials/entity_scripts/sit.js +++ b/scripts/tutorials/entity_scripts/sit.js @@ -12,9 +12,9 @@ Script.include("/~/system/libraries/utils.js"); if (!String.prototype.startsWith) { String.prototype.startsWith = function(searchString, position){ - position = position || 0; - return this.substr(position, searchString.length) === searchString; - }; + position = position || 0; + return this.substr(position, searchString.length) === searchString; + }; } var SETTING_KEY = "com.highfidelity.avatar.isSitting"; @@ -122,10 +122,20 @@ this.rolesToOverride = function() { return MyAvatar.getAnimationRoles().filter(function(role) { - return !(role.startsWith("right") || role.startsWith("left")); + return !(role.startsWith("right") || role.startsWith("left")); }); } + // Handler for user changing the avatar model while sitting. There's currently an issue with changing avatar models while override role animations are applied, + // so to avoid that problem, re-apply the role overrides once the model has finished changing. + this.modelURLChangeFinished = function () { + print("Sitter's model has FINISHED changing. Reapply anim role overrides."); + var roles = this.rolesToOverride(); + for (i in roles) { + MyAvatar.overrideRoleAnimation(roles[i], ANIMATION_URL, ANIMATION_FPS, true, ANIMATION_FIRST_FRAME, ANIMATION_LAST_FRAME); + } + } + this.sitDown = function() { if (this.checkSeatForAvatar()) { print("Someone is already sitting in that chair."); @@ -164,12 +174,14 @@ return { headType: 0 }; }, ["headType"]); Script.update.connect(this, this.update); + MyAvatar.onLoadComplete.connect(this, this.modelURLChangeFinished); } this.standUp = function() { print("Standing up (" + this.entityID + ")"); MyAvatar.removeAnimationStateHandler(this.animStateHandlerID); Script.update.disconnect(this, this.update); + MyAvatar.onLoadComplete.disconnect(this, this.modelURLChangeFinished); if (MyAvatar.sessionUUID === this.getSeatUser()) { this.setSeatUser(null); @@ -331,7 +343,7 @@ } this.cleanupOverlay(); } - + this.clickDownOnEntity = function (id, event) { if (isInEditMode()) { return; @@ -340,4 +352,4 @@ this.sitDown(); } } -}); \ No newline at end of file +}); From 6ddb91e5939632fe2a16b8a44768b09d93cb6230 Mon Sep 17 00:00:00 2001 From: Alexia Mandeville Date: Mon, 12 Mar 2018 13:17:48 -0700 Subject: [PATCH 004/499] Revert "Updating default mouse pitch/yaw input to be more stabilized" This reverts commit 2598be16f81734e86e00f2789bc2111bcdf448b8. --- interface/src/avatar/MyAvatar.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 8bbbef041a..53116d81f3 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -67,8 +67,8 @@ using namespace std; const float DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES = 30.0f; -const float YAW_SPEED_DEFAULT = 75.0f; // degrees/sec -const float PITCH_SPEED_DEFAULT = 50.0f; // degrees/sec +const float YAW_SPEED_DEFAULT = 100.0f; // degrees/sec +const float PITCH_SPEED_DEFAULT = 75.0f; // degrees/sec const float MAX_BOOST_SPEED = 0.5f * DEFAULT_AVATAR_MAX_WALKING_SPEED; // action motor gets additive boost below this speed const float MIN_AVATAR_SPEED = 0.05f; From c5b8a2d06ecd933279334ae47858c1a0ef6756c4 Mon Sep 17 00:00:00 2001 From: Alexia Mandeville Date: Mon, 12 Mar 2018 13:18:02 -0700 Subject: [PATCH 005/499] Revert "Increasing speed on mousescroll - zooming in/out of avatar" This reverts commit 748507f1e357b7a03177f847c63362297de9663e. --- interface/src/avatar/MyAvatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 53116d81f3..b6fa3fde96 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -2229,7 +2229,7 @@ void MyAvatar::updateActionMotor(float deltaTime) { } float boomChange = getDriveKey(ZOOM); - _boomLength += 4.0f * _boomLength * boomChange + boomChange * boomChange; + _boomLength += 2.0f * _boomLength * boomChange + boomChange * boomChange; _boomLength = glm::clamp(_boomLength, ZOOM_MIN, ZOOM_MAX); } From 31ab39834461afb448bd3a21c55c94bd4cb6a87f Mon Sep 17 00:00:00 2001 From: Alexia Mandeville Date: Thu, 29 Mar 2018 11:20:01 -0700 Subject: [PATCH 006/499] Moving user height and clarifying verbiage --- interface/src/ui/PreferencesDialog.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 8860f4dab7..b309ecd5e3 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -170,16 +170,6 @@ void setupPreferences() { // which can't be changed across domain switches. Having these values loaded up when you load the Dialog each time // is a way around this, therefore they're not specified here but in the QML. } - { - auto getter = [=]()->float { return myAvatar->getUserHeight(); }; - auto setter = [=](float value) { myAvatar->setUserHeight(value); }; - auto preference = new SpinnerPreference(AVATAR_TUNING, "User height (meters)", getter, setter); - preference->setMin(1.0f); - preference->setMax(2.2f); - preference->setDecimals(3); - preference->setStep(0.001f); - preferences->addPreference(preference); - } { auto getter = [=]()->QString { return myAvatar->getAnimGraphOverrideUrl().toString(); }; @@ -216,6 +206,17 @@ void setupPreferences() { preferences->addPreference(new CheckPreference(MOVEMENT, "Advanced movement for hand controllers", getter, setter)); } + { + auto getter = [=]()->float { return myAvatar->getUserHeight(); }; + auto setter = [=](float value) { myAvatar->setUserHeight(value); }; + auto preference = new SpinnerPreference(MOVEMENT, "User real-world height (meters)", getter, setter); + preference->setMin(1.0f); + preference->setMax(2.2f); + preference->setDecimals(3); + preference->setStep(0.001f); + preferences->addPreference(preference); + } + static const QString AVATAR_CAMERA{ "Mouse Sensitivity" }; { auto getter = [=]()->float { return myAvatar->getPitchSpeed(); }; From da4f2b8c2f1810528cac4001aa9f97b3a2c30326 Mon Sep 17 00:00:00 2001 From: Gabriel Calero Date: Fri, 30 Mar 2018 15:34:00 -0300 Subject: [PATCH 007/499] Fix zoom in unresponsive in radar mode --- scripts/system/+android/radar.js | 47 +++++++++++++++++--------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/scripts/system/+android/radar.js b/scripts/system/+android/radar.js index 455299dd5f..2b87f8955d 100644 --- a/scripts/system/+android/radar.js +++ b/scripts/system/+android/radar.js @@ -21,7 +21,7 @@ function printd(str) { } var radar = false; -var radarHeight = 10; // camera position meters above the avatar +var radarHeight = MyAvatar.position.y + 10; // camera position (absolute y) var tablet; var RADAR_CAMERA_OFFSET = -1; // 1 meter below the avatar @@ -46,11 +46,11 @@ var uniqueColor; function moveTo(position) { if (radar) { MyAvatar.position = position; - Camera.position = Vec3.sum(MyAvatar.position, { - x : 0, + Camera.position = { + x : MyAvatar.position.x, y : radarHeight, - z : 0 - }); + z : MyAvatar.position.z + }; } } @@ -386,12 +386,12 @@ function pinchUpdate(event) { radarHeight -= pinchIncrement; } } - var deltaHeight = avatarY + radarHeight - Camera.position.y; - Camera.position = Vec3.sum(Camera.position, { - x : 0, - y : deltaHeight, - z : 0 - }); + Camera.position = { + x: Camera.position.x, + y:radarHeight, + z:Camera.position.z + }; + if (!draggingCamera) { startedDraggingCamera = true; draggingCamera = true; @@ -401,7 +401,8 @@ function pinchUpdate(event) { } function isInsideSquare(coords0, coords1, halfside) { - return Math.abs(coords0.x - coords1.x) <= halfside + return coords0 != undefined && coords1!= undefined && + Math.abs(coords0.x - coords1.x) <= halfside && Math.abs(coords0.y - coords1.y) <= halfside; } @@ -412,7 +413,7 @@ function dragScrollUpdate(event) { // drag management var pickRay = Camera.computePickRay(event.x, event.y); var dragAt = Vec3.sum(pickRay.origin, Vec3.multiply(pickRay.direction, - radarHeight)); + radarHeight-MyAvatar.position.y)); if (lastDragAt === undefined || lastDragAt === null) { lastDragAt = dragAt; @@ -722,7 +723,7 @@ function Teleporter() { return { dragTeleportBegin : function(event) { printd("[newTeleport] TELEPORT began"); - var overlayDimensions = entityIconModelDimensions(); + var overlayDimensions = entityIconModelDimensions(MyAvatar.position.y); // var destination = computeDestination(event, MyAvatar.position, // Camera.position, radarHeight); // Dimension teleport and cancel overlays (not show them yet) @@ -843,7 +844,7 @@ var avatarIconDimensionsVal = { }; function avatarIconPlaneDimensions() { // given the current height, give a size - var xy = -0.003531 * radarHeight + 0.1; + var xy = -0.003531 * (radarHeight - MyAvatar.position.y) + 0.1; avatarIconDimensionsVal.x = Math.abs(xy); avatarIconDimensionsVal.y = Math.abs(xy); // reuse object @@ -1165,9 +1166,10 @@ var entityIconModelDimensionsVal = { y : 0.00001, z : 0 }; -function entityIconModelDimensions() { +function entityIconModelDimensions(y) { // given the current height, give a size - var xz = -0.002831 * radarHeight + 0.1; + // TODO: receive entity.position.y and substract to radarHeight + var xz = -0.002831 * (radarHeight - y) + 0.1; entityIconModelDimensionsVal.x = xz; entityIconModelDimensionsVal.z = xz; // reuse object @@ -1177,8 +1179,8 @@ function entityIconModelDimensions() { * entityIconPlaneDimensions: similar to entityIconModelDimensions but using xy * plane */ -function entityIconPlaneDimensions() { - var dim = entityIconModelDimensions(); +function entityIconPlaneDimensions(y) { + var dim = entityIconModelDimensions(y); var z = dim.z; dim.z = dim.y; dim.y = z; @@ -1255,15 +1257,15 @@ function hideAllEntitiesIcons() { function renderAllEntitiesIcons() { var entityPos; var entityProps; - var iconDimensions = entityIconModelDimensions(); - var planeDimensions = entityIconPlaneDimensions(); // plane overlays uses - // xy instead of xz + for ( var QUuid in entitiesData) { if (entitiesData.hasOwnProperty(QUuid)) { entityProps = Entities.getEntityProperties(QUuid, [ "position", "visible" ]); if (entityProps != null) { entityPos = entityProps.position; + var planeDimensions = entityIconPlaneDimensions(entityPos.y); // plane overlays uses + // xy instead of xz if (entitiesData[QUuid].icon != undefined && entityPos) { var iconPos = findLineToHeightIntersectionCoords( entityPos.x, @@ -1276,6 +1278,7 @@ function renderAllEntitiesIcons() { printd("entity icon pos bad for " + QUuid); continue; } + var iconDimensions = entityIconModelDimensions(entityPos.y); var dimensions = entitiesData[QUuid].planar ? planeDimensions : iconDimensions; Overlays.editOverlay(entitiesData[QUuid].icon, { From fc86525863df9eb5a2a01c948fa08f30e6cf616d Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 4 Apr 2018 12:00:06 +0200 Subject: [PATCH 008/499] Cleaned up a bit shadow map clear --- libraries/render-utils/src/RenderShadowTask.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index 69c5b3c689..faa5889307 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -149,9 +149,7 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext, con batch.setStateScissorRect(viewport); batch.setFramebuffer(fbo); - batch.clearFramebuffer( - gpu::Framebuffer::BUFFER_COLOR0 | gpu::Framebuffer::BUFFER_DEPTH, - vec4(vec3(1.0, 1.0, 1.0), 0.0), 1.0, 0, true); + batch.clearDepthFramebuffer(1.0, false); glm::mat4 projMat; Transform viewMat; From 36bc5f841627e170cb0d15c35586106d5c176eb5 Mon Sep 17 00:00:00 2001 From: Gabriel Calero Date: Thu, 5 Apr 2018 15:35:08 -0300 Subject: [PATCH 009/499] Fix the view snap when user starts zooming --- scripts/system/+android/radar.js | 37 ++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/scripts/system/+android/radar.js b/scripts/system/+android/radar.js index 2b87f8955d..120bec33c3 100644 --- a/scripts/system/+android/radar.js +++ b/scripts/system/+android/radar.js @@ -21,7 +21,8 @@ function printd(str) { } var radar = false; -var radarHeight = MyAvatar.position.y + 10; // camera position (absolute y) +var RADAR_HEIGHT_INIT_DELTA = 10; +var radarHeight = MyAvatar.position.y + RADAR_HEIGHT_INIT_DELTA; // camera position (absolute y) var tablet; var RADAR_CAMERA_OFFSET = -1; // 1 meter below the avatar @@ -386,6 +387,7 @@ function pinchUpdate(event) { radarHeight -= pinchIncrement; } } + Camera.position = { x: Camera.position.x, y:radarHeight, @@ -655,6 +657,7 @@ function Teleporter() { return; } + Camera.position = Vec3.sum(Camera.position, { x : xDelta, y : 0, @@ -1301,11 +1304,12 @@ function startRadar() { saveAllOthersAvatarsData(); Camera.mode = "independent"; - Camera.position = Vec3.sum(MyAvatar.position, { - x : 0, - y : radarHeight, - z : 0 - }); + Camera.position = { + x : MyAvatar.position.x, + y : radarHeight, + z : MyAvatar.position.z + }; + Camera.orientation = Quat.fromPitchYawRollDegrees(-90, 0, 0); radar = true; @@ -1394,15 +1398,25 @@ function connectRadarModeEvents() { Controller.keyPressEvent.connect(keyPressEvent); Controller.mousePressEvent.connect(mousePress); // single click/touch Controller.touchUpdateEvent.connect(touchUpdate); + Window.domainChanged.connect(domainChanged); MyAvatar.positionGoneTo.connect(positionGoneTo); } -function positionGoneTo() { - Camera.position = Vec3.sum(MyAvatar.position, { - x : 0, +function domainChanged() { + radarHeight = MyAvatar.position.y + RADAR_HEIGHT_INIT_DELTA; + Camera.position = { + x : MyAvatar.position.x, y : radarHeight, - z : 0 - }); + z : MyAvatar.position.z + }; +} + +function positionGoneTo() { + Camera.position = { + x : MyAvatar.position.x, + y : radarHeight, + z : MyAvatar.position.z + }; } function disconnectRadarModeEvents() { @@ -1411,6 +1425,7 @@ function disconnectRadarModeEvents() { Controller.mousePressEvent.disconnect(mousePress); Controller.touchUpdateEvent.disconnect(touchUpdate); MyAvatar.positionGoneTo.disconnect(positionGoneTo); + Window.domainChanged.disconnect(domainChanged); } function init() { From 573f399023eafd625212284f827ea3207f006f76 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 6 Apr 2018 14:45:16 +0200 Subject: [PATCH 010/499] Fixed incorrect shadow frustum far clip computation due to not taking into account shadow receivers --- .../render-utils/src/RenderShadowTask.cpp | 27 ++++++++++-------- libraries/render-utils/src/RenderShadowTask.h | 2 +- libraries/render/src/render/CullTask.cpp | 28 +++++++++++++------ libraries/render/src/render/CullTask.h | 2 +- 4 files changed, 38 insertions(+), 21 deletions(-) diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index faa5889307..fbb4bba263 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -230,12 +230,11 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende const auto queryResolution = setupOutput.getN(2); // Fetch and cull the items from the scene - // Enable models to not cast shadows (otherwise, models will always cast shadows) - static const auto shadowCasterFilter = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered().withTagBits(tagBits, tagMask).withShadowCaster(); + static const auto shadowCasterReceiverFilter = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered().withTagBits(tagBits, tagMask); - const auto fetchInput = FetchSpatialTree::Inputs(shadowCasterFilter, queryResolution).asVarying(); + const auto fetchInput = FetchSpatialTree::Inputs(shadowCasterReceiverFilter, queryResolution).asVarying(); const auto shadowSelection = task.addJob("FetchShadowTree", fetchInput); - const auto selectionInputs = FetchSpatialSelection::Inputs(shadowSelection, shadowCasterFilter).asVarying(); + const auto selectionInputs = FetchSpatialSelection::Inputs(shadowSelection, shadowCasterReceiverFilter).asVarying(); const auto shadowItems = task.addJob("FetchShadowSelection", selectionInputs); // Cull objects that are not visible in camera view. Hopefully the cull functor only performs LOD culling, not @@ -259,21 +258,22 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende char jobName[64]; sprintf(jobName, "ShadowCascadeSetup%d", i); const auto cascadeSetupOutput = task.addJob(jobName, i, _cullFunctor, tagBits, tagMask); - const auto shadowFilter = cascadeSetupOutput.getN(0); + const auto shadowRenderFilter = cascadeSetupOutput.getN(0); + const auto shadowBoundsFilter = cascadeSetupOutput.getN(1); auto antiFrustum = render::Varying(ViewFrustumPointer()); - cascadeFrustums[i] = cascadeSetupOutput.getN(1); + cascadeFrustums[i] = cascadeSetupOutput.getN(2); if (i > 1) { antiFrustum = cascadeFrustums[i - 2]; } // CPU jobs: finer grained culling - const auto cullInputs = CullShapeBounds::Inputs(sortedShapes, shadowFilter, antiFrustum).asVarying(); + const auto cullInputs = CullShapeBounds::Inputs(sortedShapes, shadowRenderFilter, shadowBoundsFilter, antiFrustum).asVarying(); const auto culledShadowItemsAndBounds = task.addJob("CullShadowCascade", cullInputs, shadowCullFunctor, RenderDetails::SHADOW); // GPU jobs: Render to shadow map sprintf(jobName, "RenderShadowMap%d", i); task.addJob(jobName, culledShadowItemsAndBounds, shapePlumber, i); - task.addJob("ShadowCascadeTeardown", shadowFilter); + task.addJob("ShadowCascadeTeardown", shadowRenderFilter); } task.addJob("ShadowTeardown", setupOutput); @@ -404,7 +404,11 @@ void RenderShadowCascadeSetup::run(const render::RenderContextPointer& renderCon const auto globalShadow = lightStage->getCurrentKeyShadow(); if (globalShadow && _cascadeIndexgetCascadeCount()) { - output.edit0() = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered().withTagBits(_tagBits, _tagMask).withShadowCaster(); + auto baseFilter = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered().withTagBits(_tagBits, _tagMask); + // Second item filter is to filter items to keep in shadow frustum computation (here we need to keep shadow receivers) + output.edit1() = baseFilter; + // First item filter is to filter items to render in shadow map (so only keep casters) + output.edit0() = baseFilter.withShadowCaster(); // Set the keylight render args auto& cascade = globalShadow->getCascade(_cascadeIndex); @@ -417,10 +421,11 @@ void RenderShadowCascadeSetup::run(const render::RenderContextPointer& renderCon texelSize *= minTexelCount; _cullFunctor._minSquareSize = texelSize * texelSize; - output.edit1() = cascadeFrustum; + output.edit2() = cascadeFrustum; } else { output.edit0() = ItemFilter::Builder::nothing(); - output.edit1() = ViewFrustumPointer(); + output.edit1() = ItemFilter::Builder::nothing(); + output.edit2() = ViewFrustumPointer(); } } diff --git a/libraries/render-utils/src/RenderShadowTask.h b/libraries/render-utils/src/RenderShadowTask.h index 98b70c0c9f..19ffcb4234 100644 --- a/libraries/render-utils/src/RenderShadowTask.h +++ b/libraries/render-utils/src/RenderShadowTask.h @@ -118,7 +118,7 @@ private: class RenderShadowCascadeSetup { public: - using Outputs = render::VaryingSet2; + using Outputs = render::VaryingSet3; using JobModel = render::Job::ModelO; RenderShadowCascadeSetup(unsigned int cascadeIndex, RenderShadowTask::CullFunctor& cullFunctor, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00) : diff --git a/libraries/render/src/render/CullTask.cpp b/libraries/render/src/render/CullTask.cpp index f04427540a..b5819f114f 100644 --- a/libraries/render/src/render/CullTask.cpp +++ b/libraries/render/src/render/CullTask.cpp @@ -368,17 +368,19 @@ void CullShapeBounds::run(const RenderContextPointer& renderContext, const Input RenderArgs* args = renderContext->args; const auto& inShapes = inputs.get0(); - const auto& filter = inputs.get1(); - const auto& antiFrustum = inputs.get2(); + const auto& cullFilter = inputs.get1(); + const auto& boundsFilter = inputs.get2(); + const auto& antiFrustum = inputs.get3(); auto& outShapes = outputs.edit0(); auto& outBounds = outputs.edit1(); outShapes.clear(); outBounds = AABox(); - if (!filter.selectsNothing()) { + if (!cullFilter.selectsNothing() || !boundsFilter.selectsNothing()) { auto& details = args->_details.edit(_detailType); Test test(_cullFunctor, args, details, antiFrustum); + auto scene = args->_scene; for (auto& inItems : inShapes) { auto key = inItems.first; @@ -393,16 +395,26 @@ void CullShapeBounds::run(const RenderContextPointer& renderContext, const Input if (antiFrustum == nullptr) { for (auto& item : inItems.second) { if (test.solidAngleTest(item.bound) && test.frustumTest(item.bound)) { - outItems->second.emplace_back(item); - outBounds += item.bound; + const auto shapeKey = scene->getItem(item.id).getKey(); + if (cullFilter.test(shapeKey)) { + outItems->second.emplace_back(item); + } + if (boundsFilter.test(shapeKey)) { + outBounds += item.bound; + } } } } else { for (auto& item : inItems.second) { if (test.solidAngleTest(item.bound) && test.frustumTest(item.bound) && test.antiFrustumTest(item.bound)) { - outItems->second.emplace_back(item); - outBounds += item.bound; - } + const auto shapeKey = scene->getItem(item.id).getKey(); + if (cullFilter.test(shapeKey)) { + outItems->second.emplace_back(item); + } + if (boundsFilter.test(shapeKey)) { + outBounds += item.bound; + } + } } } details._rendered += (int)outItems->second.size(); diff --git a/libraries/render/src/render/CullTask.h b/libraries/render/src/render/CullTask.h index 3c5a30de89..47abe8a960 100644 --- a/libraries/render/src/render/CullTask.h +++ b/libraries/render/src/render/CullTask.h @@ -110,7 +110,7 @@ namespace render { class CullShapeBounds { public: - using Inputs = render::VaryingSet3; + using Inputs = render::VaryingSet4; using Outputs = render::VaryingSet2; using JobModel = Job::ModelIO; From d5c252c9ad70cfb2e46c95b75cd3a71d7b8f5196 Mon Sep 17 00:00:00 2001 From: Cristian Duarte Date: Mon, 9 Apr 2018 16:24:03 -0300 Subject: [PATCH 011/499] Use MyAvatar.goToLocation in radar teleport. Use MyAvatar.goToLocation in radar teleport to prevent synchronization issues that make it fail occasionally when directly modifying its world position. It will work just as teleport.js does. --- scripts/system/+android/radar.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/system/+android/radar.js b/scripts/system/+android/radar.js index 120bec33c3..8100cc0887 100644 --- a/scripts/system/+android/radar.js +++ b/scripts/system/+android/radar.js @@ -46,11 +46,11 @@ var uniqueColor; function moveTo(position) { if (radar) { - MyAvatar.position = position; + MyAvatar.goToLocation(position, false); Camera.position = { - x : MyAvatar.position.x, + x : position.x, y : radarHeight, - z : MyAvatar.position.z + z : position.z }; } } From 63e17e87b0fa4e00db8b871e731c34684a1f4f08 Mon Sep 17 00:00:00 2001 From: Gabriel Calero Date: Tue, 10 Apr 2018 19:21:23 -0300 Subject: [PATCH 012/499] Fix radar initial position. Clean radar.js --- scripts/system/+android/radar.js | 232 ++----------------------------- 1 file changed, 8 insertions(+), 224 deletions(-) diff --git a/scripts/system/+android/radar.js b/scripts/system/+android/radar.js index 8100cc0887..67ba896207 100644 --- a/scripts/system/+android/radar.js +++ b/scripts/system/+android/radar.js @@ -90,46 +90,6 @@ function keyPressEvent(event) { } } -function actionOnObjectFromEvent(event) { - var rayIntersection = findRayIntersection(Camera.computePickRay(event.x, - event.y)); - if (rayIntersection && rayIntersection.intersects - && rayIntersection.overlayID) { - printd("found overlayID touched " + rayIntersection.overlayID); - if (entitiesByOverlayID[rayIntersection.overlayID]) { - var entity = Entities.getEntityProperties( - entitiesByOverlayID[rayIntersection.overlayID], - [ "sourceUrl" ]); - App.openUrl(entity.sourceUrl); - return true; - } - } - if (rayIntersection && rayIntersection.intersects - && rayIntersection.entityID && rayIntersection.properties) { - printd("found " + rayIntersection.entityID + " of type " - + rayIntersection.properties.type); - if (rayIntersection.properties.type == "Web") { - printd("found web element to " - + rayIntersection.properties.sourceUrl); - App.openUrl(rayIntersection.properties.sourceUrl); - return true; - } - } - return false; -} - -function mousePress(event) { - mousePressOrTouchEnd(event); -} - -function mousePressOrTouchEnd(event) { - if (radar) { - if (actionOnObjectFromEvent(event)) { - return; - } - } -} - function toggleRadarMode() { if (radar) { endRadar(); @@ -230,9 +190,6 @@ function touchEnd(event) { if (analyzeDoubleTap(event)) return; // double tap detected, finish - if (radar) { - mousePressOrTouchEnd(event); - } } /** @@ -726,7 +683,7 @@ function Teleporter() { return { dragTeleportBegin : function(event) { printd("[newTeleport] TELEPORT began"); - var overlayDimensions = entityIconModelDimensions(MyAvatar.position.y); + var overlayDimensions = teleportIconModelDimensions(MyAvatar.position.y); // var destination = computeDestination(event, MyAvatar.position, // Camera.position, radarHeight); // Dimension teleport and cancel overlays (not show them yet) @@ -1125,39 +1082,10 @@ function renderAllOthersAvatarIcons() { } } -function entityAdded(entityID) { - printd("Entity added " + entityID); - var props = Entities.getEntityProperties(entityID, [ "type" ]); - printd("Entity added " + entityID + " PROPS " + JSON.stringify(props)); - if (props && props.type == "Web") { - printd("Entity Web added " + entityID); - saveEntityData(entityID, true); - } -} - -function entityRemoved(entityID) { - printd("Entity removed " + entityID); - var props = Entities.getEntityProperties(entityID, [ "type" ]); - if (props && props.type == "Web") { - print("Entity Web removed " + entityID); - removeEntityData(entityID); - } -} - /******************************************************************************* * Entities (to remark) cache structure for showing entities markers ******************************************************************************/ -var entitiesData = {}; // by entityID -var entitiesByOverlayID = {}; // by overlayID -var entitiesIcons = []; // a parallel list of icons (overlays) to easily run - // through - -var ICON_ENTITY_WEB_MODEL_URL = Script.resolvePath("../assets/images/web.svg"); -var ICON_ENTITY_IMG_MODEL_URL = Script - .resolvePath("../assets/models/teleport-cancel.fbx"); // FIXME - use - // correct - // model&texture var ICON_ENTITY_DEFAULT_DIMENSIONS = { x : 0.10, y : 0.00001, @@ -1169,7 +1097,7 @@ var entityIconModelDimensionsVal = { y : 0.00001, z : 0 }; -function entityIconModelDimensions(y) { +function teleportIconModelDimensions(y) { // given the current height, give a size // TODO: receive entity.position.y and substract to radarHeight var xz = -0.002831 * (radarHeight - y) + 0.1; @@ -1178,122 +1106,6 @@ function entityIconModelDimensions(y) { // reuse object return entityIconModelDimensionsVal; } -/* - * entityIconPlaneDimensions: similar to entityIconModelDimensions but using xy - * plane - */ -function entityIconPlaneDimensions(y) { - var dim = entityIconModelDimensions(y); - var z = dim.z; - dim.z = dim.y; - dim.y = z; - return dim; -} - -function currentOverlayForEntity(QUuid) { - if (entitiesData[QUuid] != undefined) { - return entitiesData[QUuid].icon; - } else { - return null; - } -} - -function saveEntityData(QUuid, planar) { - if (QUuid == null) - return; - var entity = Entities.getEntityProperties(QUuid, [ "position" ]); - printd("entity added save entity " + QUuid); - if (entitiesData[QUuid] != undefined) { - entitiesData[QUuid].position = entity.position; - } else { - var entityIcon = Overlays.addOverlay("image3d", { - subImage : { - x : 0, - y : 0, - width : 150, - height : 150 - }, - url : ICON_ENTITY_WEB_MODEL_URL, - dimensions : ICON_ENTITY_DEFAULT_DIMENSIONS, - visible : false, - ignoreRayIntersection : false, - orientation : Quat.fromPitchYawRollDegrees(-90, 0, 0) - }); - - entitiesIcons.push(entityIcon); - entitiesData[QUuid] = { - position : entity.position, - icon : entityIcon - }; - entitiesByOverlayID[entityIcon] = QUuid; - } -} - -function removeEntityData(QUuid) { - if (QUuid == null) - return; - - var itsOverlay = currentOverlayForEntity(QUuid); - if (itsOverlay != null) { - Overlays.deleteOverlay(itsOverlay); - delete entitiesByOverlayID[itsOverlay]; - } - var idx = entitiesIcons.indexOf(itsOverlay); - entitiesIcons.splice(idx, 1); - - delete entitiesData[QUuid]; -} - -/******************************************************************************* - * Entities to remark Icon/Markers rendering - ******************************************************************************/ - -function hideAllEntitiesIcons() { - var len = entitiesIcons.length; - for (var i = 0; i < len; i++) { - Overlays.editOverlay(entitiesIcons[i], { - visible : false - }); - } -} - -function renderAllEntitiesIcons() { - var entityPos; - var entityProps; - - for ( var QUuid in entitiesData) { - if (entitiesData.hasOwnProperty(QUuid)) { - entityProps = Entities.getEntityProperties(QUuid, [ "position", - "visible" ]); - if (entityProps != null) { - entityPos = entityProps.position; - var planeDimensions = entityIconPlaneDimensions(entityPos.y); // plane overlays uses - // xy instead of xz - if (entitiesData[QUuid].icon != undefined && entityPos) { - var iconPos = findLineToHeightIntersectionCoords( - entityPos.x, - entityPos.y - + RADAR_ICONS_APPARENT_DISTANCE_TO_AVATAR_BASE, - entityPos.z, Camera.position.x, Camera.position.y, - Camera.position.z, Camera.position.y - - RADAR_CAMERA_DISTANCE_TO_ICONS); - if (!iconPos) { - printd("entity icon pos bad for " + QUuid); - continue; - } - var iconDimensions = entityIconModelDimensions(entityPos.y); - var dimensions = entitiesData[QUuid].planar ? planeDimensions - : iconDimensions; - Overlays.editOverlay(entitiesData[QUuid].icon, { - visible : entityProps.visible, - dimensions : dimensions, - position : iconPos - }); - } - } - } - } -} /******************************************************************************* * @@ -1304,11 +1116,7 @@ function startRadar() { saveAllOthersAvatarsData(); Camera.mode = "independent"; - Camera.position = { - x : MyAvatar.position.x, - y : radarHeight, - z : MyAvatar.position.z - }; + initCameraOverMyAvatar(); Camera.orientation = Quat.fromPitchYawRollDegrees(-90, 0, 0); radar = true; @@ -1326,7 +1134,6 @@ function endRadar() { Controller.setVPadEnabled(true); disconnectRadarModeEvents(); - hideAllEntitiesIcons(); hideAllAvatarIcons(); } @@ -1360,12 +1167,10 @@ function updateRadar() { // Update avatar icons if (startedDraggingCamera) { hideAllAvatarIcons(); - hideAllEntitiesIcons(); startedDraggingCamera = false; } else if (!draggingCamera) { renderMyAvatarIcon(); renderAllOthersAvatarIcons(); - renderAllEntitiesIcons(); } } @@ -1373,36 +1178,15 @@ function valueIfDefined(value) { return value !== undefined ? value : ""; } -function entitiesAnalysis() { - var ids = Entities.findEntitiesInFrustum(Camera.frustum); - var entities = []; - for (var i = 0; i < ids.length; i++) { - var id = ids[i]; - var properties = Entities.getEntityProperties(id); - entities.push({ - id : id, - name : properties.name, - type : properties.type, - url : properties.type == "Model" ? properties.modelURL : "", - sourceUrl : properties.sourceUrl, - locked : properties.locked, - visible : properties.visible, - drawCalls : valueIfDefined(properties.renderInfo.drawCalls), - hasScript : properties.script !== "" - }); - } -} - function connectRadarModeEvents() { Script.update.connect(updateRadar); // 60Hz loop Controller.keyPressEvent.connect(keyPressEvent); - Controller.mousePressEvent.connect(mousePress); // single click/touch Controller.touchUpdateEvent.connect(touchUpdate); Window.domainChanged.connect(domainChanged); MyAvatar.positionGoneTo.connect(positionGoneTo); } -function domainChanged() { +function initCameraOverMyAvatar() { radarHeight = MyAvatar.position.y + RADAR_HEIGHT_INIT_DELTA; Camera.position = { x : MyAvatar.position.x, @@ -1411,6 +1195,10 @@ function domainChanged() { }; } +function domainChanged() { + initCameraOverMyAvatar(); +} + function positionGoneTo() { Camera.position = { x : MyAvatar.position.x, @@ -1422,7 +1210,6 @@ function positionGoneTo() { function disconnectRadarModeEvents() { Script.update.disconnect(updateRadar); Controller.keyPressEvent.disconnect(keyPressEvent); - Controller.mousePressEvent.disconnect(mousePress); Controller.touchUpdateEvent.disconnect(touchUpdate); MyAvatar.positionGoneTo.disconnect(positionGoneTo); Window.domainChanged.disconnect(domainChanged); @@ -1436,7 +1223,4 @@ function init() { AvatarList.avatarAddedEvent.connect(avatarAdded); AvatarList.avatarRemovedEvent.connect(avatarRemoved); - - Entities.addingEntity.connect(entityAdded); - Entities.deletingEntity.connect(entityRemoved); } From 86cfb1448a19eee833920804515a55eccd2c3698 Mon Sep 17 00:00:00 2001 From: Triplelexx Date: Mon, 16 Apr 2018 21:54:14 +0100 Subject: [PATCH 013/499] move inspect script --- {script-archive => scripts/system}/inspect.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {script-archive => scripts/system}/inspect.js (100%) diff --git a/script-archive/inspect.js b/scripts/system/inspect.js similarity index 100% rename from script-archive/inspect.js rename to scripts/system/inspect.js From 8a5d80de312fbe7512a6a1b40fe18c2c32edaf16 Mon Sep 17 00:00:00 2001 From: vladest Date: Tue, 17 Apr 2018 19:51:24 +0200 Subject: [PATCH 014/499] Fix Desktop double windows --- interface/src/Application.cpp | 7 +------ interface/src/ui/PreferencesDialog.cpp | 7 +++++++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index aec31f2de4..a2d117e6ee 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -6518,12 +6518,7 @@ void Application::showDialog(const QUrl& widgetUrl, const QUrl& tabletUrl, const if (onTablet) { toggleTabletUI(true); } - } - - if (!onTablet) { - DependencyManager::get()->show(widgetUrl, name); - } - if (tablet->getToolbarMode()) { + } else { DependencyManager::get()->show(widgetUrl, name); } } diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 289166648e..a678a1b94b 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -51,6 +51,13 @@ void setupPreferences() { auto preference = new AvatarPreference(AVATAR_BASICS, "Appearance", getter, setter); preferences->addPreference(preference); } + // UI + static const QString GRAPHICS_QUALITY { "Graphics Quality" }; + { + auto getter = []()->float { return DependencyManager::get()->getLODLevel(); }; + auto setter = [](float value) { FaceTracker::setEyeDeflection(value); }; + preferences->addPreference(new SliderPreference(GRAPHICS_QUALITY, "World Detail", getter, setter)); + } // UI static const QString UI_CATEGORY { "User Interface" }; From c402cb2c19f93b7e4d7b619171996514deaa70aa Mon Sep 17 00:00:00 2001 From: vladest Date: Tue, 17 Apr 2018 19:51:43 +0200 Subject: [PATCH 015/499] Fix Desktop double windows --- .../dialogs/GraphicsPreferencesDialog.qml | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 interface/resources/qml/hifi/dialogs/GraphicsPreferencesDialog.qml diff --git a/interface/resources/qml/hifi/dialogs/GraphicsPreferencesDialog.qml b/interface/resources/qml/hifi/dialogs/GraphicsPreferencesDialog.qml new file mode 100644 index 0000000000..eaab5b8173 --- /dev/null +++ b/interface/resources/qml/hifi/dialogs/GraphicsPreferencesDialog.qml @@ -0,0 +1,29 @@ +// +// AdvancedPreferencesDialog.qml +// +// Created by Brad Hefta-Gaub on 20 Jan 2018 +// Copyright 2018 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.5 +import Qt.labs.settings 1.0 + +import "../../dialogs" + +PreferencesDialog { + id: root + objectName: "GraphicsPreferencesDialog" + title: "Graphics Settings" + showCategories: ["Graphics Quality" ] + property var settings: Settings { + category: root.objectName + property alias x: root.x + property alias y: root.y + property alias width: root.width + property alias height: root.height + } +} + From ee1738adac9aa0070bd42eb35c802cd5e647d25b Mon Sep 17 00:00:00 2001 From: vladest Date: Tue, 17 Apr 2018 21:58:53 +0200 Subject: [PATCH 016/499] Add stubs for graphics settings. Add avatar collision setting --- interface/src/ui/PreferencesDialog.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index a678a1b94b..ac7a4f0610 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -55,8 +55,11 @@ void setupPreferences() { static const QString GRAPHICS_QUALITY { "Graphics Quality" }; { auto getter = []()->float { return DependencyManager::get()->getLODLevel(); }; - auto setter = [](float value) { FaceTracker::setEyeDeflection(value); }; + auto setter = [](float value) { }; preferences->addPreference(new SliderPreference(GRAPHICS_QUALITY, "World Detail", getter, setter)); + auto getterSQ = []()->float { return 1.0; }; + auto setterSQ = [](float value) { }; + preferences->addPreference(new SliderPreference(GRAPHICS_QUALITY, "Shadow Quality", getterSQ, setterSQ)); } // UI @@ -182,6 +185,13 @@ void setupPreferences() { preferences->addPreference(preference); } + { + auto getter = [=]()->bool { return myAvatar->getCollisionsEnabled(); }; + auto setter = [=](bool value) { myAvatar->setCollisionsEnabled(value); }; + auto preference = new CheckPreference(AVATAR_TUNING, "Enable Avatar collisions", getter, setter); + preferences->addPreference(preference); + } + static const QString FACE_TRACKING{ "Face Tracking" }; { auto getter = []()->float { return DependencyManager::get()->getEyeClosingThreshold(); }; From 120de92c9e284bf5b792bc8d85845536583204f8 Mon Sep 17 00:00:00 2001 From: Gabriel Calero Date: Wed, 18 Apr 2018 15:52:02 -0300 Subject: [PATCH 017/499] Add login activity --- android/app/src/main/AndroidManifest.xml | 9 +- android/app/src/main/cpp/native.cpp | 76 ++++- .../hifiinterface/GotoActivity.java | 14 +- .../hifiinterface/HomeActivity.java | 105 +++--- .../hifiinterface/InterfaceActivity.java | 8 +- .../hifiinterface/LoginActivity.java | 106 ++++++ .../hifiinterface/PermissionChecker.java | 2 +- .../QtPreloader/QtPreloader.java | 315 ------------------ .../hifiinterface/SplashActivity.java | 32 ++ .../qt5/android/bindings/QtActivity.java | 8 +- .../app/src/main/res/drawable/hifi_header.xml | 50 +++ .../src/main/res/drawable/rounded_button.xml | 24 ++ .../src/main/res/drawable/rounded_edit.xml | 7 + .../app/src/main/res/layout/activity_goto.xml | 4 +- .../app/src/main/res/layout/activity_home.xml | 25 +- .../src/main/res/layout/activity_login.xml | 106 ++++++ .../src/main/res/layout/activity_splash.xml | 12 + android/app/src/main/res/values/colors.xml | 5 + android/app/src/main/res/values/strings.xml | 7 + android/app/src/main/res/values/styles.xml | 9 +- interface/src/AndroidHelper.cpp | 29 ++ interface/src/AndroidHelper.h | 16 +- interface/src/Application.cpp | 4 + 23 files changed, 577 insertions(+), 396 deletions(-) create mode 100644 android/app/src/main/java/io/highfidelity/hifiinterface/LoginActivity.java delete mode 100644 android/app/src/main/java/io/highfidelity/hifiinterface/QtPreloader/QtPreloader.java create mode 100644 android/app/src/main/java/io/highfidelity/hifiinterface/SplashActivity.java create mode 100644 android/app/src/main/res/drawable/hifi_header.xml create mode 100644 android/app/src/main/res/drawable/rounded_button.xml create mode 100644 android/app/src/main/res/drawable/rounded_edit.xml create mode 100644 android/app/src/main/res/layout/activity_login.xml create mode 100644 android/app/src/main/res/layout/activity_splash.xml diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index ed9caee58b..8828335cd1 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -47,8 +47,9 @@ - + android:theme="@style/AppTheme" /> + + + diff --git a/android/app/src/main/cpp/native.cpp b/android/app/src/main/cpp/native.cpp index c71be76b3e..3fad01db9b 100644 --- a/android/app/src/main/cpp/native.cpp +++ b/android/app/src/main/cpp/native.cpp @@ -22,7 +22,9 @@ #include #include "AndroidHelper.h" -QAndroidJniObject __activity; +QAndroidJniObject __interfaceActivity; +QAndroidJniObject __loginActivity; +QAndroidJniObject __loadCompleteListener; void tempMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { if (!message.isEmpty()) { @@ -142,16 +144,16 @@ void unpackAndroidAssets() { extern "C" { JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnCreate(JNIEnv* env, jobject obj, jobject instance, jobject asset_mgr) { - qDebug() << "nativeOnCreate On thread " << QThread::currentThreadId(); g_assetManager = AAssetManager_fromJava(env, asset_mgr); - __activity = QAndroidJniObject(instance); + qRegisterMetaType("QAndroidJniObject"); + __interfaceActivity = QAndroidJniObject(instance); auto oldMessageHandler = qInstallMessageHandler(tempMessageHandler); unpackAndroidAssets(); qInstallMessageHandler(oldMessageHandler); QObject::connect(&AndroidHelper::instance(), &AndroidHelper::androidActivityRequested, [](const QString& a) { QAndroidJniObject string = QAndroidJniObject::fromString(a); - __activity.callMethod("openGotoActivity", "(Ljava/lang/String;)V", string.object()); + __interfaceActivity.callMethod("openGotoActivity", "(Ljava/lang/String;)V", string.object()); }); } @@ -167,15 +169,12 @@ JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeGotoUr } JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnPause(JNIEnv* env, jobject obj) { - qDebug() << "nativeOnPause"; } JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnResume(JNIEnv* env, jobject obj) { - qDebug() << "nativeOnResume"; } JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnExitVr(JNIEnv* env, jobject obj) { - qDebug() << "nativeOnCreate On thread " << QThread::currentThreadId(); } JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeGoBackFromAndroidActivity(JNIEnv *env, jobject instance) { @@ -204,4 +203,67 @@ JNIEXPORT jstring JNICALL Java_io_highfidelity_hifiinterface_HifiUtils_getCurren return env->NewStringUTF(str.toLatin1().data()); } +JNIEXPORT void JNICALL +Java_io_highfidelity_hifiinterface_LoginActivity_nativeLogin(JNIEnv *env, jobject instance, + jstring username_, jstring password_) { + const char *c_username = env->GetStringUTFChars(username_, 0); + const char *c_password = env->GetStringUTFChars(password_, 0); + QString username = QString(c_username); + QString password = QString(c_password); + env->ReleaseStringUTFChars(username_, c_username); + env->ReleaseStringUTFChars(password_, c_password); + + QSharedPointer accountManager = AndroidHelper::instance().getAccountManager(); + + __loginActivity = QAndroidJniObject(instance); + + QObject::connect(accountManager.data(), &AccountManager::loginComplete, [](const QUrl& authURL) { + AndroidHelper::instance().notifyLoginComplete(true); + }); + + QObject::connect(accountManager.data(), &AccountManager::loginFailed, []() { + AndroidHelper::instance().notifyLoginComplete(false); + }); + + QObject::connect(&AndroidHelper::instance(), &AndroidHelper::loginComplete, [](bool success) { + jboolean jSuccess = (jboolean) success; + __loginActivity.callMethod("handleLoginCompleted", "(Z)V", jSuccess); + }); + + QMetaObject::invokeMethod(accountManager.data(), "requestAccessToken", Q_ARG(const QString&, username), Q_ARG(const QString&, password)); +} + +JNIEXPORT void JNICALL +Java_io_highfidelity_hifiinterface_SplashActivity_registerLoadCompleteListener(JNIEnv *env, + jobject instance) { + + __loadCompleteListener = QAndroidJniObject(instance); + + QObject::connect(&AndroidHelper::instance(), &AndroidHelper::qtAppLoadComplete, []() { + + __loadCompleteListener.callMethod("onAppLoadedComplete", "()V"); + __interfaceActivity.callMethod("onAppLoadedComplete", "()V"); + + QObject::disconnect(&AndroidHelper::instance(), &AndroidHelper::qtAppLoadComplete, nullptr, + nullptr); + }); + +} +JNIEXPORT jboolean JNICALL +Java_io_highfidelity_hifiinterface_HomeActivity_nativeIsLoggedIn(JNIEnv *env, jobject instance) { + return AndroidHelper::instance().getAccountManager()->isLoggedIn(); +} + +JNIEXPORT void JNICALL +Java_io_highfidelity_hifiinterface_HomeActivity_nativeLogout(JNIEnv *env, jobject instance) { + AndroidHelper::instance().getAccountManager()->logout(); +} + +JNIEXPORT jstring JNICALL +Java_io_highfidelity_hifiinterface_HomeActivity_nativeGetDisplayName(JNIEnv *env, + jobject instance) { + QString username = AndroidHelper::instance().getAccountManager()->getAccountInfo().getUsername(); + return env->NewStringUTF(username.toLatin1().data()); +} + } diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/GotoActivity.java b/android/app/src/main/java/io/highfidelity/hifiinterface/GotoActivity.java index 65221bc21c..f1ecc21d84 100644 --- a/android/app/src/main/java/io/highfidelity/hifiinterface/GotoActivity.java +++ b/android/app/src/main/java/io/highfidelity/hifiinterface/GotoActivity.java @@ -9,7 +9,6 @@ import android.support.v7.widget.Toolbar; import android.view.KeyEvent; import android.view.MenuItem; import android.view.View; -import android.view.inputmethod.EditorInfo; import android.widget.EditText; import java.net.URI; @@ -17,6 +16,8 @@ import java.net.URISyntaxException; public class GotoActivity extends AppCompatActivity { + public static final String PARAM_DOMAIN_URL = "domain_url"; + private EditText mUrlEditText; private AppCompatButton mGoBtn; @@ -69,15 +70,10 @@ public class GotoActivity extends AppCompatActivity { urlString = "hifi://" + urlString; } - Intent intent = new Intent(this, InterfaceActivity.class); - intent.putExtra(InterfaceActivity.DOMAIN_URL, urlString); + Intent intent = new Intent(); + intent.putExtra(GotoActivity.PARAM_DOMAIN_URL, urlString); + setResult(RESULT_OK, intent); finish(); - if (getIntent() != null && - getIntent().hasExtra(HomeActivity.PARAM_NOT_START_INTERFACE_ACTIVITY) && - getIntent().getBooleanExtra(HomeActivity.PARAM_NOT_START_INTERFACE_ACTIVITY, false)) { - intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); - } - startActivity(intent); } } diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/HomeActivity.java b/android/app/src/main/java/io/highfidelity/hifiinterface/HomeActivity.java index ed442e2d8d..117e1f2cc4 100644 --- a/android/app/src/main/java/io/highfidelity/hifiinterface/HomeActivity.java +++ b/android/app/src/main/java/io/highfidelity/hifiinterface/HomeActivity.java @@ -1,9 +1,7 @@ package io.highfidelity.hifiinterface; -import android.app.ProgressDialog; import android.content.Intent; import android.graphics.Color; -import android.os.AsyncTask; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.design.widget.NavigationView; @@ -22,18 +20,23 @@ import android.widget.TabHost; import android.widget.TabWidget; import android.widget.TextView; -import io.highfidelity.hifiinterface.QtPreloader.QtPreloader; import io.highfidelity.hifiinterface.view.DomainAdapter; public class HomeActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener { + public native boolean nativeIsLoggedIn(); + public native void nativeLogout(); + public native String nativeGetDisplayName(); + /** * Set this intent extra param to NOT start a new InterfaceActivity after a domain is selected" */ - public static final String PARAM_NOT_START_INTERFACE_ACTIVITY = "not_start_interface_activity"; + //public static final String PARAM_NOT_START_INTERFACE_ACTIVITY = "not_start_interface_activity"; + + public static final int ENTER_DOMAIN_URL = 1; + private DomainAdapter domainAdapter; private DrawerLayout mDrawerLayout; - private ProgressDialog mDialog; private NavigationView mNavigationView; @Override @@ -89,15 +92,7 @@ public class HomeActivity extends AppCompatActivity implements NavigationView.On @Override public void onItemClick(View view, int position, DomainAdapter.Domain domain) { - Intent intent = new Intent(HomeActivity.this, InterfaceActivity.class); - intent.putExtra(InterfaceActivity.DOMAIN_URL, domain.url); - HomeActivity.this.finish(); - if (getIntent() != null && - getIntent().hasExtra(PARAM_NOT_START_INTERFACE_ACTIVITY) && - getIntent().getBooleanExtra(PARAM_NOT_START_INTERFACE_ACTIVITY, false)) { - intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); - } - startActivity(intent); + gotoDomain(domain.url); } }); domainsView.setAdapter(domainAdapter); @@ -112,49 +107,28 @@ public class HomeActivity extends AppCompatActivity implements NavigationView.On searchTextView.setTextAppearance(R.style.SearchText); } - if (getIntent() == null || - !getIntent().hasExtra(PARAM_NOT_START_INTERFACE_ACTIVITY) || - !getIntent().getBooleanExtra(PARAM_NOT_START_INTERFACE_ACTIVITY, false)) { - preloadQt(); - showActivityIndicator(); - } + updateLoginMenu(); } - private void showActivityIndicator() { - if (mDialog == null) { - mDialog = new ProgressDialog(this); - } - mDialog.setMessage("Please wait..."); - mDialog.setCancelable(false); - mDialog.show(); - } - - private void cancelActivityIndicator() { - if (mDialog != null) { - mDialog.cancel(); + private void updateLoginMenu() { + TextView loginOption = findViewById(R.id.login); + TextView logoutOption = findViewById(R.id.logout); + if (nativeIsLoggedIn()) { + loginOption.setVisibility(View.GONE); + logoutOption.setVisibility(View.VISIBLE); + } else { + loginOption.setVisibility(View.VISIBLE); + logoutOption.setVisibility(View.GONE); } } - private AsyncTask preloadTask; - - private void preloadQt() { - if (preloadTask == null) { - preloadTask = new AsyncTask() { - @Override - protected Object doInBackground(Object[] objects) { - new QtPreloader(HomeActivity.this).initQt(); - runOnUiThread(new Runnable() { - @Override - public void run() { - cancelActivityIndicator(); - } - }); - return null; - } - }; - preloadTask.execute(); - } + private void gotoDomain(String domainUrl) { + Intent intent = new Intent(HomeActivity.this, InterfaceActivity.class); + intent.putExtra(InterfaceActivity.DOMAIN_URL, domainUrl); + HomeActivity.this.finish(); + intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); + startActivity(intent); } @Override @@ -181,7 +155,6 @@ public class HomeActivity extends AppCompatActivity implements NavigationView.On @Override protected void onDestroy() { - cancelActivityIndicator(); super.onDestroy(); } @@ -190,11 +163,33 @@ public class HomeActivity extends AppCompatActivity implements NavigationView.On switch(item.getItemId()) { case R.id.action_goto: Intent i = new Intent(this, GotoActivity.class); - startActivity(i); - return true; - case R.id.action_settings: + startActivityForResult(i, ENTER_DOMAIN_URL); return true; } return false; } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == ENTER_DOMAIN_URL && resultCode == RESULT_OK) { + gotoDomain(data.getStringExtra(GotoActivity.PARAM_DOMAIN_URL)); + } + } + + @Override + protected void onStart() { + super.onStart(); + updateLoginMenu(); + } + + public void onLoginClicked(View view) { + Intent intent = new Intent(this, LoginActivity.class); + startActivity(intent); + } + + public void onLogoutClicked(View view) { + nativeLogout(); + updateLoginMenu(); + } } diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java b/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java index 678f7e8aac..2b86abc9da 100644 --- a/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java +++ b/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java @@ -63,6 +63,7 @@ public class InterfaceActivity extends QtActivity { @Override public void onCreate(Bundle savedInstanceState) { + super.isLoading = true; Intent intent = getIntent(); if (intent.hasExtra(DOMAIN_URL) && !intent.getStringExtra(DOMAIN_URL).isEmpty()) { intent.putExtra("applicationArguments", "--url "+intent.getStringExtra(DOMAIN_URL)); @@ -112,6 +113,8 @@ public class InterfaceActivity extends QtActivity { } } }); + startActivity(new Intent(this, SplashActivity.class)); + } @Override @@ -201,7 +204,6 @@ public class InterfaceActivity extends QtActivity { switch (activityName) { case "Goto": { Intent intent = new Intent(this, HomeActivity.class); - intent.putExtra(HomeActivity.PARAM_NOT_START_INTERFACE_ACTIVITY, true); startActivity(intent); break; } @@ -212,4 +214,8 @@ public class InterfaceActivity extends QtActivity { } } + public void onAppLoadedComplete() { + super.isLoading = false; + } + } \ No newline at end of file diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/LoginActivity.java b/android/app/src/main/java/io/highfidelity/hifiinterface/LoginActivity.java new file mode 100644 index 0000000000..9fd256aa82 --- /dev/null +++ b/android/app/src/main/java/io/highfidelity/hifiinterface/LoginActivity.java @@ -0,0 +1,106 @@ +package io.highfidelity.hifiinterface; + +import android.app.ProgressDialog; +import android.support.annotation.MainThread; +import android.support.v7.app.AppCompatActivity; +import android.os.Bundle; +import android.util.Log; +import android.view.KeyEvent; +import android.view.View; +import android.view.inputmethod.EditorInfo; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.Toast; + +public class LoginActivity extends AppCompatActivity { + + public native void nativeLogin(String username, String password); + + private EditText mUsername; + private EditText mPassword; + private TextView mError; + private Button mLoginButton; + + private ProgressDialog mDialog; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_login); + + mUsername = findViewById(R.id.username); + mPassword = findViewById(R.id.password); + mError = findViewById(R.id.error); + mLoginButton = findViewById(R.id.loginButton); + + mPassword.setOnEditorActionListener( + new TextView.OnEditorActionListener() { + @Override + public boolean onEditorAction(TextView textView, int actionId, KeyEvent keyEvent) { + if (actionId == EditorInfo.IME_ACTION_DONE) { + mLoginButton.performClick(); + return true; + } + return false; + } + }); + + } + + @Override + protected void onStop() { + super.onStop(); + cancelActivityIndicator(); + } + + public void login(View view) { + String username = mUsername.getText().toString(); + String password = mPassword.getText().toString(); + if (username.isEmpty() || password.isEmpty()) { + showError(getString(R.string.login_username_or_password_incorrect)); + } else { + mLoginButton.setEnabled(false); + hideError(); + showActivityIndicator(); + nativeLogin(username, password); + } + } + + private void showActivityIndicator() { + if (mDialog == null) { + mDialog = new ProgressDialog(this); + } + mDialog.setMessage(getString(R.string.logging_in)); + mDialog.setCancelable(false); + mDialog.show(); + } + + private void cancelActivityIndicator() { + if (mDialog != null) { + mDialog.cancel(); + } + } + private void showError(String error) { + mError.setText(error); + mError.setVisibility(View.VISIBLE); + } + + private void hideError() { + mError.setText(""); + mError.setVisibility(View.INVISIBLE); + } + + public void handleLoginCompleted(boolean success) { + runOnUiThread(() -> { + mLoginButton.setEnabled(true); + cancelActivityIndicator(); + if (success) { + finish(); + } else { + showError(getString(R.string.login_username_or_password_incorrect)); + } + }); + } + +} diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/PermissionChecker.java b/android/app/src/main/java/io/highfidelity/hifiinterface/PermissionChecker.java index b1c5f570c8..2b48d85a48 100644 --- a/android/app/src/main/java/io/highfidelity/hifiinterface/PermissionChecker.java +++ b/android/app/src/main/java/io/highfidelity/hifiinterface/PermissionChecker.java @@ -64,7 +64,7 @@ public class PermissionChecker extends Activity { private void launchActivityWithPermissions(){ finish(); - Intent i = new Intent(this, HomeActivity.class); + Intent i = new Intent(this, InterfaceActivity.class); startActivity(i); finish(); } diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/QtPreloader/QtPreloader.java b/android/app/src/main/java/io/highfidelity/hifiinterface/QtPreloader/QtPreloader.java deleted file mode 100644 index d9ecdb9710..0000000000 --- a/android/app/src/main/java/io/highfidelity/hifiinterface/QtPreloader/QtPreloader.java +++ /dev/null @@ -1,315 +0,0 @@ -package io.highfidelity.hifiinterface.QtPreloader; - -import android.content.ComponentName; -import android.content.Context; -import android.content.pm.ComponentInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.res.AssetManager; -import android.os.Bundle; -import android.util.Log; - -import org.qtproject.qt5.android.bindings.QtApplication; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.lang.reflect.Method; -import java.util.ArrayList; - -import dalvik.system.DexClassLoader; - -/** - * Created by Gabriel Calero & Cristian Duarte on 3/22/18. - */ - -public class QtPreloader { - - public String ENVIRONMENT_VARIABLES = "QT_USE_ANDROID_NATIVE_DIALOGS=1"; - private ComponentInfo m_contextInfo; - private String[] m_qtLibs = null; // required qt libs - private Context m_context; - - private static final String DEX_PATH_KEY = "dex.path"; - private static final String LIB_PATH_KEY = "lib.path"; - private static final String NATIVE_LIBRARIES_KEY = "native.libraries"; - private static final String ENVIRONMENT_VARIABLES_KEY = "environment.variables"; - private static final String BUNDLED_LIBRARIES_KEY = "bundled.libraries"; - private static final String BUNDLED_IN_LIB_RESOURCE_ID_KEY = "android.app.bundled_in_lib_resource_id"; - private static final String BUNDLED_IN_ASSETS_RESOURCE_ID_KEY = "android.app.bundled_in_assets_resource_id"; - private static final String MAIN_LIBRARY_KEY = "main.library"; - - private static final int BUFFER_SIZE = 1024; - - public QtPreloader(Context context) { - m_context = context; - } - - public void initQt() { - - try { - m_contextInfo = m_context.getPackageManager().getActivityInfo(new ComponentName("io.highfidelity.hifiinterface", "io.highfidelity.hifiinterface.InterfaceActivity"), - PackageManager.GET_META_DATA); - - if (m_contextInfo.metaData.containsKey("android.app.qt_libs_resource_id")) { - int resourceId = m_contextInfo.metaData.getInt("android.app.qt_libs_resource_id"); - m_qtLibs = m_context.getResources().getStringArray(resourceId); - } - ArrayList libraryList = new ArrayList<>(); - String localPrefix = m_context.getApplicationInfo().dataDir + "/"; - String pluginsPrefix = localPrefix + "qt-reserved-files/"; - cleanOldCacheIfNecessary(localPrefix, pluginsPrefix); - extractBundledPluginsAndImports(pluginsPrefix); - - for (String lib : m_qtLibs) { - libraryList.add(localPrefix + "lib/lib" + lib + ".so"); - } - - if (m_contextInfo.metaData.containsKey("android.app.load_local_libs")) { - String[] extraLibs = m_contextInfo.metaData.getString("android.app.load_local_libs").split(":"); - for (String lib : extraLibs) { - if (lib.length() > 0) { - if (lib.startsWith("lib/")) { - libraryList.add(localPrefix + lib); - } else { - libraryList.add(pluginsPrefix + lib); - } - } - } - } - - Bundle loaderParams = new Bundle(); - loaderParams.putString(DEX_PATH_KEY, new String()); - - loaderParams.putStringArrayList(NATIVE_LIBRARIES_KEY, libraryList); - - loaderParams.putString(ENVIRONMENT_VARIABLES_KEY, ENVIRONMENT_VARIABLES - + "\tQML2_IMPORT_PATH=" + pluginsPrefix + "/qml" - + "\tQML_IMPORT_PATH=" + pluginsPrefix + "/imports" - + "\tQT_PLUGIN_PATH=" + pluginsPrefix + "/plugins"); - - - // add all bundled Qt libs to loader params - ArrayList libs = new ArrayList<>(); - - String libName = m_contextInfo.metaData.getString("android.app.lib_name"); - loaderParams.putString(MAIN_LIBRARY_KEY, libName); //main library contains main() function - loaderParams.putStringArrayList(BUNDLED_LIBRARIES_KEY, libs); - - // load and start QtLoader class - DexClassLoader classLoader = new DexClassLoader(loaderParams.getString(DEX_PATH_KEY), // .jar/.apk files - m_context.getDir("outdex", Context.MODE_PRIVATE).getAbsolutePath(), // directory where optimized DEX files should be written. - loaderParams.containsKey(LIB_PATH_KEY) ? loaderParams.getString(LIB_PATH_KEY) : null, // libs folder (if exists) - m_context.getClassLoader()); // parent loader - - Class loaderClass = classLoader.loadClass(loaderClassName()); // load QtLoader class - Object qtLoader = loaderClass.newInstance(); // create an instance - Method prepareAppMethod = qtLoader.getClass().getMethod("loadApplication", - contextClassName(), - ClassLoader.class, - Bundle.class); - prepareAppMethod.invoke(qtLoader, m_context, classLoader, loaderParams); - - // now load the application library so it's accessible from this class loader - if (libName != null) { - System.loadLibrary(libName); - } - } catch (Exception e) { - Log.e(QtApplication.QtTAG, "Error pre-loading HiFi Qt app", e); - } - } - - protected String loaderClassName() { - return "org.qtproject.qt5.android.QtActivityDelegate"; - } - - protected Class contextClassName() { - return android.app.Activity.class; - } - - - private void deleteRecursively(File directory) { - File[] files = directory.listFiles(); - if (files != null) { - for (File file : files) { - if (file.isDirectory()) { - deleteRecursively(file); - } else { - file.delete(); - } - } - - directory.delete(); - } - } - - private void cleanOldCacheIfNecessary(String oldLocalPrefix, String localPrefix) { - File newCache = new File(localPrefix); - if (!newCache.exists()) { - { - File oldPluginsCache = new File(oldLocalPrefix + "plugins/"); - if (oldPluginsCache.exists() && oldPluginsCache.isDirectory()) { - deleteRecursively(oldPluginsCache); - } - } - - { - File oldImportsCache = new File(oldLocalPrefix + "imports/"); - if (oldImportsCache.exists() && oldImportsCache.isDirectory()) { - deleteRecursively(oldImportsCache); - } - } - - { - File oldQmlCache = new File(oldLocalPrefix + "qml/"); - if (oldQmlCache.exists() && oldQmlCache.isDirectory()) { - deleteRecursively(oldQmlCache); - } - } - } - } - - static private void copyFile(InputStream inputStream, OutputStream outputStream) - throws IOException { - byte[] buffer = new byte[BUFFER_SIZE]; - - int count; - while ((count = inputStream.read(buffer)) > 0) { - outputStream.write(buffer, 0, count); - } - } - - private void copyAsset(String source, String destination) - throws IOException { - // Already exists, we don't have to do anything - File destinationFile = new File(destination); - if (destinationFile.exists()) { - return; - } - - File parentDirectory = destinationFile.getParentFile(); - if (!parentDirectory.exists()) { - parentDirectory.mkdirs(); - } - - destinationFile.createNewFile(); - - AssetManager assetsManager = m_context.getAssets(); - InputStream inputStream = assetsManager.open(source); - OutputStream outputStream = new FileOutputStream(destinationFile); - copyFile(inputStream, outputStream); - - inputStream.close(); - outputStream.close(); - } - - private static void createBundledBinary(String source, String destination) - throws IOException { - // Already exists, we don't have to do anything - File destinationFile = new File(destination); - if (destinationFile.exists()) { - return; - } - - File parentDirectory = destinationFile.getParentFile(); - if (!parentDirectory.exists()) { - parentDirectory.mkdirs(); - } - - destinationFile.createNewFile(); - - InputStream inputStream = new FileInputStream(source); - OutputStream outputStream = new FileOutputStream(destinationFile); - copyFile(inputStream, outputStream); - - inputStream.close(); - outputStream.close(); - } - - private boolean cleanCacheIfNecessary(String pluginsPrefix, long packageVersion) { - File versionFile = new File(pluginsPrefix + "cache.version"); - - long cacheVersion = 0; - if (versionFile.exists() && versionFile.canRead()) { - try { - DataInputStream inputStream = new DataInputStream(new FileInputStream(versionFile)); - cacheVersion = inputStream.readLong(); - inputStream.close(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - if (cacheVersion != packageVersion) { - deleteRecursively(new File(pluginsPrefix)); - return true; - } else { - return false; - } - } - - private void extractBundledPluginsAndImports(String pluginsPrefix) throws IOException { - String libsDir = m_context.getApplicationInfo().nativeLibraryDir + "/"; - long packageVersion = -1; - try { - PackageInfo packageInfo = m_context.getPackageManager().getPackageInfo(m_context.getPackageName(), 0); - packageVersion = packageInfo.lastUpdateTime; - } catch (Exception e) { - e.printStackTrace(); - } - - - if (!cleanCacheIfNecessary(pluginsPrefix, packageVersion)) { - return; - } - - { - File versionFile = new File(pluginsPrefix + "cache.version"); - - File parentDirectory = versionFile.getParentFile(); - if (!parentDirectory.exists()) { - parentDirectory.mkdirs(); - } - - versionFile.createNewFile(); - - DataOutputStream outputStream = new DataOutputStream(new FileOutputStream(versionFile)); - outputStream.writeLong(packageVersion); - outputStream.close(); - } - - { - String key = BUNDLED_IN_LIB_RESOURCE_ID_KEY; - if (m_contextInfo.metaData.containsKey(key)) { - String[] list = m_context.getResources().getStringArray(m_contextInfo.metaData.getInt(key)); - - for (String bundledImportBinary : list) { - String[] split = bundledImportBinary.split(":"); - String sourceFileName = libsDir + split[0]; - String destinationFileName = pluginsPrefix + split[1]; - createBundledBinary(sourceFileName, destinationFileName); - } - } - } - - { - String key = BUNDLED_IN_ASSETS_RESOURCE_ID_KEY; - if (m_contextInfo.metaData.containsKey(key)) { - String[] list = m_context.getResources().getStringArray(m_contextInfo.metaData.getInt(key)); - - for (String fileName : list) { - String[] split = fileName.split(":"); - String sourceFileName = split[0]; - String destinationFileName = pluginsPrefix + split[1]; - copyAsset(sourceFileName, destinationFileName); - } - } - - } - } -} diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/SplashActivity.java b/android/app/src/main/java/io/highfidelity/hifiinterface/SplashActivity.java new file mode 100644 index 0000000000..b663a3e396 --- /dev/null +++ b/android/app/src/main/java/io/highfidelity/hifiinterface/SplashActivity.java @@ -0,0 +1,32 @@ +package io.highfidelity.hifiinterface; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; + +public class SplashActivity extends Activity { + + private native void registerLoadCompleteListener(); + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_splash); + registerLoadCompleteListener(); + } + + @Override + protected void onStart() { + super.onStart(); + } + + @Override + protected void onStop() { + super.onStop(); + } + + public void onAppLoadedComplete() { + startActivity(new Intent(this, HomeActivity.class)); + finish(); + } +} diff --git a/android/app/src/main/java/org/qtproject/qt5/android/bindings/QtActivity.java b/android/app/src/main/java/org/qtproject/qt5/android/bindings/QtActivity.java index ed55c16cde..887d27dba4 100644 --- a/android/app/src/main/java/org/qtproject/qt5/android/bindings/QtActivity.java +++ b/android/app/src/main/java/org/qtproject/qt5/android/bindings/QtActivity.java @@ -68,6 +68,8 @@ public class QtActivity extends Activity { public final String QT_ANDROID_DEFAULT_THEME = QT_ANDROID_THEMES[0]; // sets the default theme. private QtActivityLoader m_loader = new QtActivityLoader(this); + public boolean isLoading; + public QtActivity() { } @@ -499,7 +501,11 @@ public class QtActivity extends Activity { @Override protected void onPause() { super.onPause(); - QtApplication.invokeDelegate(); + // GC: this trick allow us to show a splash activity until Qt app finishes + // loading + if (!isLoading) { + QtApplication.invokeDelegate(); + } } //--------------------------------------------------------------------------- diff --git a/android/app/src/main/res/drawable/hifi_header.xml b/android/app/src/main/res/drawable/hifi_header.xml new file mode 100644 index 0000000000..9f7c85297a --- /dev/null +++ b/android/app/src/main/res/drawable/hifi_header.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/rounded_button.xml b/android/app/src/main/res/drawable/rounded_button.xml new file mode 100644 index 0000000000..11a9f90c8b --- /dev/null +++ b/android/app/src/main/res/drawable/rounded_button.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/rounded_edit.xml b/android/app/src/main/res/drawable/rounded_edit.xml new file mode 100644 index 0000000000..3c1cac4d1d --- /dev/null +++ b/android/app/src/main/res/drawable/rounded_edit.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/activity_goto.xml b/android/app/src/main/res/layout/activity_goto.xml index 7f4e7d5fcf..2d5943e15d 100644 --- a/android/app/src/main/res/layout/activity_goto.xml +++ b/android/app/src/main/res/layout/activity_goto.xml @@ -3,8 +3,8 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/root_activity_goto" - android:layout_width="match_parent" - android:layout_height="match_parent" + android:layout_width="wrap_content" + android:layout_height="wrap_content" tools:context="io.highfidelity.hifiinterface.GotoActivity"> + > + + + + + diff --git a/android/app/src/main/res/layout/activity_login.xml b/android/app/src/main/res/layout/activity_login.xml new file mode 100644 index 0000000000..ecf72b94bf --- /dev/null +++ b/android/app/src/main/res/layout/activity_login.xml @@ -0,0 +1,106 @@ + + + + + + + + + + + +