diff --git a/interface/resources/qml/dialogs/TabletLoginDialog.qml b/interface/resources/qml/dialogs/TabletLoginDialog.qml index a37f5be595..30c3e678b4 100644 --- a/interface/resources/qml/dialogs/TabletLoginDialog.qml +++ b/interface/resources/qml/dialogs/TabletLoginDialog.qml @@ -23,7 +23,7 @@ TabletModalWindow { property var eventBridge; signal sendToScript(var message); property bool isHMD: false - + property bool gotoPreviousApp: false; color: hifi.colors.baseGray property int colorScheme: hifi.colorSchemes.dark @@ -66,8 +66,11 @@ TabletModalWindow { HifiConstants { id: hifi } onCanceled: { - if (loginDialogRoot.Stack.view !== null) { - loginDialogRoot.Stack.view.pop() + if (loginDialogRoot.Stack.view) { + loginDialogRoot.Stack.view.pop(); + } else if (gotoPreviousApp) { + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + tablet.returnToPreviousApp(); } else { Tablet.getTablet("com.highfidelity.interface.tablet.system").gotoHomeScreen(); } diff --git a/interface/resources/qml/hifi/tablet/TabletGeneralPreferences.qml b/interface/resources/qml/hifi/tablet/TabletGeneralPreferences.qml index 6fc29ac920..d23daddd8d 100644 --- a/interface/resources/qml/hifi/tablet/TabletGeneralPreferences.qml +++ b/interface/resources/qml/hifi/tablet/TabletGeneralPreferences.qml @@ -18,7 +18,7 @@ StackView { initialItem: root objectName: "stack" property string title: "General Settings" - + property alias gotoPreviousApp: root.gotoPreviousApp; property var eventBridge; signal sendToScript(var message); diff --git a/interface/resources/qml/hifi/tablet/TabletRoot.qml b/interface/resources/qml/hifi/tablet/TabletRoot.qml index f5144e698f..446d4c91ff 100644 --- a/interface/resources/qml/hifi/tablet/TabletRoot.qml +++ b/interface/resources/qml/hifi/tablet/TabletRoot.qml @@ -14,6 +14,8 @@ Item { property string subMenu: "" signal showDesktop(); property bool shown: true + property int currentApp: -1; + property alias tabletApps: tabletApps function setOption(value) { option = value; @@ -56,13 +58,48 @@ Item { } function loadSource(url) { + tabletApps.clear(); loader.source = ""; // make sure we load the qml fresh each time. loader.source = url; + tabletApps.append({"appUrl": url, "isWebUrl": false, "scriptUrl": "", "appWebUrl": ""}); + } + + function loadQMLOnTop(url) { + tabletApps.append({"appUrl": url, "isWebUrl": false, "scriptUrl": "", "appWebUrl": ""}); + loader.source = ""; + loader.source = tabletApps.get(currentApp).appUrl; + if (loader.item.hasOwnProperty("gotoPreviousApp")) { + loader.item.gotoPreviousApp = true; + } + } + + function loadWebOnTop(url, injectJavaScriptUrl) { + tabletApps.append({"appUrl": loader.source, "isWebUrl": true, "scriptUrl": injectJavaScriptUrl, "appWebUrl": url}); + loader.item.url = tabletApps.get(currentApp).appWebUrl; + loader.item.scriptUrl = tabletApps.get(currentApp).scriptUrl; + if (loader.item.hasOwnProperty("gotoPreviousApp")) { + loader.item.gotoPreviousApp = true; + } + } + + function returnToPreviousApp() { + tabletApps.remove(currentApp); + var isWebPage = tabletApps.get(currentApp).isWebUrl; + if (isWebPage) { + var webUrl = tabletApps.get(currentApp).appWebUrl; + var scriptUrl = tabletApps.get(currentApp).scriptUrl; + loadSource("TabletWebView.qml"); + loadWebUrl(webUrl, scriptUrl); + } else { + loader.source = tabletApps.get(currentApp).appUrl; + } } function loadWebUrl(url, injectedJavaScriptUrl) { + tabletApps.clear(); loader.item.url = url; loader.item.scriptURL = injectedJavaScriptUrl; + tabletApps.append({"appUrl": "TabletWebView.qml", "isWebUrl": true, "scriptUrl": injectedJavaScriptUrl, "appWebUrl": url}); } // used to send a message from qml to interface script. @@ -97,6 +134,13 @@ Item { username = newUsername; } + ListModel { + id: tabletApps + onCountChanged: { + currentApp = count - 1 + } + } + Loader { id: loader objectName: "loader" diff --git a/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml b/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml index c96099a78a..2c8f6d9ea0 100644 --- a/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml +++ b/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml @@ -31,6 +31,7 @@ Item { property bool keyboardEnabled: false property bool keyboardRaised: false property bool punctuationMode: false + property bool gotoPreviousApp: false property var tablet; @@ -55,7 +56,13 @@ Item { } function closeDialog() { - Tablet.getTablet("com.highfidelity.interface.tablet.system").gotoHomeScreen(); + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + + if (gotoPreviousApp) { + tablet.returnToPreviousApp(); + } else { + tablet.gotoHomeScreen(); + } } Rectangle { diff --git a/libraries/script-engine/src/TabletScriptingInterface.cpp b/libraries/script-engine/src/TabletScriptingInterface.cpp index fcf41d0335..e744e83ebb 100644 --- a/libraries/script-engine/src/TabletScriptingInterface.cpp +++ b/libraries/script-engine/src/TabletScriptingInterface.cpp @@ -354,6 +354,38 @@ void TabletProxy::gotoMenuScreen(const QString& submenu) { } } +void TabletProxy::loadQMLOnTop(const QVariant& path) { + QObject* root = nullptr; + if (!_toolbarMode && _qmlTabletRoot) { + root = _qmlTabletRoot; + } else if (_toolbarMode && _desktopWindow) { + root = _desktopWindow->asQuickItem(); + } + + if (root) { + QMetaObject::invokeMethod(root, "loadQMLOnTop", Q_ARG(const QVariant&, path)); + QMetaObject::invokeMethod(root, "setShown", Q_ARG(const QVariant&, QVariant(true))); + } else { + qCDebug(scriptengine) << "tablet cannot load QML because _qmlTabletRoot is null"; + } +} + +void TabletProxy::returnToPreviousApp() { + QObject* root = nullptr; + if (!_toolbarMode && _qmlTabletRoot) { + root = _qmlTabletRoot; + } else if (_toolbarMode && _desktopWindow) { + root = _desktopWindow->asQuickItem(); + } + + if (root) { + QMetaObject::invokeMethod(root, "returnToPreviousApp"); + QMetaObject::invokeMethod(root, "setShown", Q_ARG(const QVariant&, QVariant(true))); + } else { + qCDebug(scriptengine) << "tablet cannot load QML because _qmlTabletRoot is null"; + } +} + void TabletProxy::loadQMLSource(const QVariant& path) { QObject* root = nullptr; @@ -440,6 +472,26 @@ void TabletProxy::gotoWebScreen(const QString& url) { gotoWebScreen(url, ""); } +void TabletProxy::loadWebScreenOnTop(const QVariant& url) { + loadWebScreenOnTop(url, ""); +} + +void TabletProxy::loadWebScreenOnTop(const QVariant& url, const QString& injectJavaScriptUrl) { + QObject* root = nullptr; + if (!_toolbarMode && _qmlTabletRoot) { + root = _qmlTabletRoot; + } else if (_toolbarMode && _desktopWindow) { + root = _desktopWindow->asQuickItem(); + } + + if (root) { + QMetaObject::invokeMethod(root, "loadQMLOnTop", Q_ARG(const QVariant&, QVariant(WEB_VIEW_SOURCE_URL))); + QMetaObject::invokeMethod(root, "setShown", Q_ARG(const QVariant&, QVariant(true))); + QMetaObject::invokeMethod(root, "loadWebOnTop", Q_ARG(const QVariant&, QVariant(url)), Q_ARG(const QVariant&, QVariant(injectJavaScriptUrl))); + } + _state = State::Web; +} + void TabletProxy::gotoWebScreen(const QString& url, const QString& injectedJavaScriptUrl) { QObject* root = nullptr; diff --git a/libraries/script-engine/src/TabletScriptingInterface.h b/libraries/script-engine/src/TabletScriptingInterface.h index 5029919c22..008f97222e 100644 --- a/libraries/script-engine/src/TabletScriptingInterface.h +++ b/libraries/script-engine/src/TabletScriptingInterface.h @@ -99,7 +99,7 @@ public: bool getToolbarMode() const { return _toolbarMode; } void setToolbarMode(bool toolbarMode); - void initialScreen(const QVariant& url); + Q_INVOKABLE void initialScreen(const QVariant& url); /**jsdoc * transition to the home screen @@ -120,6 +120,13 @@ public: Q_INVOKABLE void pushOntoStack(const QVariant& path); Q_INVOKABLE void popFromStack(); + Q_INVOKABLE void loadQMLOnTop(const QVariant& path); + Q_INVOKABLE void loadWebScreenOnTop(const QVariant& url); + Q_INVOKABLE void loadWebScreenOnTop(const QVariant& url, const QString& injectedJavaScriptUrl); + Q_INVOKABLE void returnToPreviousApp(); + + + /** jsdoc * Check if the tablet has a message dialog open * @function TabletProxy#isMessageDialogOpen diff --git a/scripts/system/snapshot.js b/scripts/system/snapshot.js index 8f393846c0..76f72d97e1 100644 --- a/scripts/system/snapshot.js +++ b/scripts/system/snapshot.js @@ -35,15 +35,17 @@ function shouldOpenFeedAfterShare() { function showFeedWindow() { if ((HMD.active && Settings.getValue("hmdTabletBecomesToolbar")) || (!HMD.active && Settings.getValue("desktopTabletBecomesToolbar"))) { - DialogsManager.showFeed(); - } else { tablet.loadQMLSource("TabletAddressDialog.qml"); + } else { + tablet.initialScreen("TabletAddressDialog.qml"); HMD.openTablet(); } } var outstanding; var readyData; +var shareAfterLogin = false; +var snapshotToShareAfterLogin; function onMessage(message) { // Receives message from the html dialog via the qwebchannel EventBridge. This is complicated by the following: // 1. Although we can send POJOs, we cannot receive a toplevel object. (Arrays of POJOs are fine, though.) @@ -70,7 +72,7 @@ function onMessage(message) { || (!HMD.active && Settings.getValue("desktopTabletBecomesToolbar"))) { Desktop.show("hifi/dialogs/GeneralPreferencesDialog.qml", "General Preferences"); } else { - tablet.loadQMLSource("TabletGeneralPreferences.qml"); + tablet.loadQMLOnTop("TabletGeneralPreferences.qml"); } break; case 'setOpenFeedFalse': @@ -82,26 +84,39 @@ function onMessage(message) { default: //tablet.webEventReceived.disconnect(onMessage); // <<< It's probably this that's missing?! HMD.closeTablet(); - tablet.gotoHomeScreen(); isLoggedIn = Account.isLoggedIn(); message.action.forEach(function (submessage) { if (submessage.share && !isLoggedIn) { needsLogin = true; submessage.share = false; + shareAfterLogin = true; + snapshotToShareAfterLogin = {path: submessage.localPath, href: submessage.href}; } if (submessage.share) { print('sharing', submessage.localPath); - outstanding++; + outstanding = true; Window.shareSnapshot(submessage.localPath, submessage.href); } else { print('not sharing', submessage.localPath); } + }); - if (!outstanding && shouldOpenFeedAfterShare()) { - //showFeedWindow(); + if (outstanding && shouldOpenFeedAfterShare()) { + showFeedWindow(); + outstanding = false; } if (needsLogin) { // after the possible feed, so that the login is on top - Account.checkAndSignalForAccessToken(); + var isLoggedIn = Account.isLoggedIn(); + + if (!isLoggedIn) { + if ((HMD.active && Settings.getValue("hmdTabletBecomesToolbar")) + || (!HMD.active && Settings.getValue("desktopTabletBecomesToolbar"))) { + Menu.triggerOption("Login / Sign Up"); + } else { + tablet.loadQMLOnTop("../../dialogs/TabletLoginDialog.qml"); + HMD.openTablet(); + } + } } } } @@ -235,13 +250,24 @@ function onTabletScreenChanged(type, url) { isInSnapshotReview = false; } } +function onConnected() { + if (shareAfterLogin && Account.isLoggedIn()) { + print('sharing', snapshotToShareAfterLogin.path); + Window.shareSnapshot(snapshotToShareAfterLogin.path, snapshotToShareAfterLogin.href); + shareAfterLogin = false; + if (shouldOpenFeedAfterShare()) { + showFeedWindow(); + } + } + +} button.clicked.connect(onClicked); buttonConnected = true; Window.snapshotShared.connect(snapshotShared); Window.processingGif.connect(processingGif); tablet.screenChanged.connect(onTabletScreenChanged); - +Account.usernameChanged.connect(onConnected); Script.scriptEnding.connect(function () { if (buttonConnected) { button.clicked.disconnect(onClicked);