From 4c64571234cd839de2644412495798c95acb38d2 Mon Sep 17 00:00:00 2001
From: Kevin Lee <klee@mozilla.com>
Date: Mon, 18 Jun 2018 18:13:25 -0700
Subject: [PATCH] Check if browser is an iOS uiWebView If it is, don't allow
 user to enter in 2D. Instead, prompt the user to copy the URL and open it in
 Safari.

---
 src/assets/translations.data.json     |  1 +
 src/react-components/entry-buttons.js | 11 ++++++++++
 src/react-components/info-dialog.js   | 30 +++++++++++++++++++++++++++
 src/react-components/ui-root.js       | 17 +++++++++++++--
 src/utils/vr-caps-detect.js           | 12 +++++++++--
 5 files changed, 67 insertions(+), 4 deletions(-)

diff --git a/src/assets/translations.data.json b/src/assets/translations.data.json
index 0201cf0fc..79d115995 100644
--- a/src/assets/translations.data.json
+++ b/src/assets/translations.data.json
@@ -3,6 +3,7 @@
     "entry.screen-prefix": "Enter on ",
     "entry.desktop-screen": "Screen",
     "entry.mobile-screen": "Phone",
+    "entry.mobile-safari": "Safari",
     "entry.generic-prefix": "Enter in ",
     "entry.generic-medium": "VR",
     "entry.generic-subtitle-desktop": "Oculus or SteamVR",
diff --git a/src/react-components/entry-buttons.js b/src/react-components/entry-buttons.js
index 9e8302b3c..f2551df70 100644
--- a/src/react-components/entry-buttons.js
+++ b/src/react-components/entry-buttons.js
@@ -87,6 +87,17 @@ export const DaydreamEntryButton = props => {
   return <EntryButton {...entryButtonProps} />;
 };
 
+export const SafariEntryButton = props => {
+  const entryButtonProps = {
+    ...props,
+    iconSrc: MobileScreenEntryImg,
+    prefixMessageId: "entry.screen-prefix",
+    mediumMessageId: "entry.mobile-safari"
+  };
+
+  return <EntryButton {...entryButtonProps} />;
+};
+
 export const DeviceEntryButton = props => {
   const entryButtonProps = {
     ...props,
diff --git a/src/react-components/info-dialog.js b/src/react-components/info-dialog.js
index 7a48099b4..5f0f6bd93 100644
--- a/src/react-components/info-dialog.js
+++ b/src/react-components/info-dialog.js
@@ -13,6 +13,7 @@ class InfoDialog extends Component {
     slack: Symbol("slack"),
     email_submitted: Symbol("email_submitted"),
     invite: Symbol("invite"),
+    safari: Symbol(""),
     updates: Symbol("updates"),
     report: Symbol("report"),
     help: Symbol("help"),
@@ -155,6 +156,35 @@ class InfoDialog extends Component {
           </div>
         );
         break;
+      case InfoDialog.dialogTypes.safari:
+        dialogTitle = "Open in Safari";
+        dialogBody = (
+          <div>
+            <div>
+              Hubs is not supported in your current browser on iOS. Copy and paste this link directly in Safari.
+            </div>
+            <div className="invite-form">
+              <input
+                type="text"
+                readOnly
+                onFocus={e => e.target.select()}
+                value={document.location}
+                className="invite-form__link_field"
+              />
+              <div className="invite-form__buttons">
+                {navigator.share && (
+                  <button className="invite-form__action-button" onClick={this.shareLinkClicked}>
+                    <span>Share</span>
+                  </button>
+                )}
+                <button className="invite-form__action-button" onClick={this.copyLinkClicked}>
+                  <span>{this.state.copyLinkButtonText}</span>
+                </button>
+              </div>
+            </div>
+          </div>
+        );
+        break;
       case InfoDialog.dialogTypes.updates:
         dialogTitle = "";
         dialogBody = (
diff --git a/src/react-components/ui-root.js b/src/react-components/ui-root.js
index cb69c6343..c291c9a61 100644
--- a/src/react-components/ui-root.js
+++ b/src/react-components/ui-root.js
@@ -11,7 +11,13 @@ import screenfull from "screenfull";
 
 import { lang, messages } from "../utils/i18n";
 import AutoExitWarning from "./auto-exit-warning";
-import { TwoDEntryButton, DeviceEntryButton, GenericEntryButton, DaydreamEntryButton } from "./entry-buttons.js";
+import {
+  TwoDEntryButton,
+  DeviceEntryButton,
+  GenericEntryButton,
+  DaydreamEntryButton,
+  SafariEntryButton
+} from "./entry-buttons.js";
 import { ProfileInfoHeader } from "./profile-info-header.js";
 import ProfileEntryPanel from "./profile-entry-panel";
 import InfoDialog from "./info-dialog.js";
@@ -260,6 +266,10 @@ class UIRoot extends Component {
     await this.performDirectEntryFlow(false);
   };
 
+  linkSafari = async () => {
+    this.setState({ infoDialogType: InfoDialog.dialogTypes.safari });
+  };
+
   enterVR = async () => {
     if (this.props.availableVREntryTypes.generic !== VR_DEVICE_AVAILABILITY.maybe) {
       await this.performDirectEntryFlow(true);
@@ -612,9 +622,12 @@ class UIRoot extends Component {
       this.state.entryStep === ENTRY_STEPS.start ? (
         <div className="entry-panel">
           <div className="entry-panel__button-container">
-            {this.props.availableVREntryTypes.screen !== VR_DEVICE_AVAILABILITY.no && (
+            {this.props.availableVREntryTypes.screen === VR_DEVICE_AVAILABILITY.yes && (
               <TwoDEntryButton onClick={this.enter2D} />
             )}
+            {this.props.availableVREntryTypes.safari === VR_DEVICE_AVAILABILITY.maybe && (
+              <SafariEntryButton onClick={this.linkSafari} />
+            )}
             {this.props.availableVREntryTypes.generic !== VR_DEVICE_AVAILABILITY.no && (
               <GenericEntryButton onClick={this.enterVR} />
             )}
diff --git a/src/utils/vr-caps-detect.js b/src/utils/vr-caps-detect.js
index 224f1bb49..8953f12a8 100644
--- a/src/utils/vr-caps-detect.js
+++ b/src/utils/vr-caps-detect.js
@@ -57,8 +57,16 @@ export async function getAvailableVREntryTypes() {
   const isDaydreamCapableBrowser = !!(isWebVRCapableBrowser && browser.name === "chrome" && !isSamsungBrowser);
   const isIDevice = ["iPhone", "iPad", "iPod"].indexOf(deviceDetect.device) > -1;
   const isFirefoxBrowser = browser.name === "firefox";
+  const isUIWebView = typeof navigator.mediaDevices === "undefined";
+
+  const safari = isIDevice
+    ? !isUIWebView ? VR_DEVICE_AVAILABILITY.yes : VR_DEVICE_AVAILABILITY.maybe
+    : VR_DEVICE_AVAILABILITY.no;
+
+  const screen = isInHMD
+    ? VR_DEVICE_AVAILABILITY.no
+    : isIDevice && isUIWebView ? VR_DEVICE_AVAILABILITY.maybe : VR_DEVICE_AVAILABILITY.yes;
 
-  const screen = isInHMD ? VR_DEVICE_AVAILABILITY.no : VR_DEVICE_AVAILABILITY.yes;
   let generic = mobiledetect.mobile() ? VR_DEVICE_AVAILABILITY.no : VR_DEVICE_AVAILABILITY.maybe;
   let cardboard = VR_DEVICE_AVAILABILITY.no;
 
@@ -107,5 +115,5 @@ export async function getAvailableVREntryTypes() {
     }
   }
 
-  return { screen, generic, gearvr, daydream, cardboard, isInHMD };
+  return { screen, generic, gearvr, daydream, cardboard, isInHMD, safari };
 }
-- 
GitLab