Skip to content

Commit

Permalink
Merge pull request #4721 from mozilla/bug/pinning
Browse files Browse the repository at this point in the history
Fix pinning state changes
  • Loading branch information
brianpeiris authored Oct 18, 2021
2 parents 323609e + 3eeb8b9 commit 86743cf
Show file tree
Hide file tree
Showing 8 changed files with 160 additions and 157 deletions.
2 changes: 1 addition & 1 deletion src/components/pin-networked-object-button.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ AFRAME.registerComponent("pin-networked-object-button", {
if (!NAF.utils.isMine(this.targetEl) && !NAF.utils.takeOwnership(this.targetEl)) return;

const wasPinned = this.targetEl.components.pinnable && this.targetEl.components.pinnable.data.pinned;
this.targetEl.setAttribute("pinnable", "pinned", !wasPinned);
window.APP.pinningHelper.setPinned(this.targetEl, !wasPinned);
if (!wasPinned) {
this.el.sceneEl.systems["hubs-systems"].soundEffectsSystem.playSoundOneShot(SOUND_PIN);
}
Expand Down
121 changes: 54 additions & 67 deletions src/components/pinnable.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,97 +4,84 @@ AFRAME.registerComponent("pinnable", {
},

init() {
this._fireEventsAndAnimate = this._fireEventsAndAnimate.bind(this);
this._persist = this._persist.bind(this);
this._persistAndAnimate = this._persistAndAnimate.bind(this);

// Fire pinned events when media is refreshed since the version will be bumped.
this.el.addEventListener("media_refreshed", this._fireEventsAndAnimate);
// Persist when media is refreshed since the version will be bumped.
this.el.addEventListener("media_refreshed", this._persistAndAnimate);

// Fire pinned events when page changes so we can persist the page.
this.el.addEventListener("owned-pager-page-changed", () => {
this._fireEventsAndAnimate({ animate: false });
});
this.el.addEventListener("owned-pager-page-changed", this._persist);

// Fire pinned events when video state changes so we can persist the page.
this.el.addEventListener("owned-video-state-changed", this._fireEventsAndAnimate);
this.el.addEventListener("owned-video-state-changed", this._persistAndAnimate);
},

update(oldData) {
this._fireEventsAndAnimate({ oldData });
update() {
this._animate();
},

_fireEventsAndAnimate({ oldData = {}, force = false, animate = true }) {
// We need to guard against _fireEventsAndAnimate being called during entity initialization,
// when the networked component isn't initialized yet.
if (!this.el.components.networked || !this.el.components.networked.data) return;

const isMine = NAF.utils.isMine(this.el);
_persistAndAnimate() {
this._persist();
this._animate();
},

// Avoid firing events during initialization by checking if the pin state has changed before doing so.
const pinStateChanged = !!oldData.pinned !== this.data.pinned;
_persist() {
// Re-pin or unpin entity to reflect state changes.
window.APP.pinningHelper.setPinned(this.el, this.data.pinned);
},

if (this.data.pinned) {
if (pinStateChanged || force) {
this.el.emit("pinned", { el: this.el });
}
_isMine() {
return this.el.components.networked?.data && NAF.utils.isMine(this.el);
},

const isAnimationRunning =
this.el.components["animation__pin-start"]?.animationIsPlaying ||
this.el.components["animation__pin-end"]?.animationIsPlaying;

if (isMine && animate && !isAnimationRunning) {
this.el.removeAttribute("animation__pin-start");
this.el.removeAttribute("animation__pin-end");
const currentScale = this.el.object3D.scale;

this.el.setAttribute("animation__pin-start", {
property: "scale",
dur: 200,
from: { x: currentScale.x, y: currentScale.y, z: currentScale.z },
to: { x: currentScale.x * 1.1, y: currentScale.y * 1.1, z: currentScale.z * 1.1 },
easing: "easeOutElastic"
});

this.el.setAttribute("animation__pin-end", {
property: "scale",
delay: 200,
dur: 200,
from: { x: currentScale.x * 1.1, y: currentScale.y * 1.1, z: currentScale.z * 1.1 },
to: { x: currentScale.x, y: currentScale.y, z: currentScale.z },
easing: "easeOutElastic"
});

if (this.el.components["body-helper"] && !this.el.sceneEl.systems.interaction.isHeld(this.el)) {
this.el.setAttribute("body-helper", { type: "kinematic" });
}
}
} else {
if (pinStateChanged || force) {
this.el.emit("unpinned", { el: this.el });
_animate() {
const isAnimationRunning =
this.el.components["animation__pin-start"]?.animationIsPlaying ||
this.el.components["animation__pin-end"]?.animationIsPlaying;

if (this._isMine() && this.data.pinned && !isAnimationRunning) {
this.el.removeAttribute("animation__pin-start");
this.el.removeAttribute("animation__pin-end");
const currentScale = this.el.object3D.scale;

this.el.setAttribute("animation__pin-start", {
property: "scale",
dur: 200,
from: { x: currentScale.x, y: currentScale.y, z: currentScale.z },
to: { x: currentScale.x * 1.1, y: currentScale.y * 1.1, z: currentScale.z * 1.1 },
easing: "easeOutElastic"
});

this.el.setAttribute("animation__pin-end", {
property: "scale",
delay: 200,
dur: 200,
from: { x: currentScale.x * 1.1, y: currentScale.y * 1.1, z: currentScale.z * 1.1 },
to: { x: currentScale.x, y: currentScale.y, z: currentScale.z },
easing: "easeOutElastic"
});

if (this.el.components["body-helper"] && !this.el.sceneEl.systems.interaction.isHeld(this.el)) {
this.el.setAttribute("body-helper", { type: "kinematic" });
}
}
},

isHeld(el) {
const { leftHand, rightHand, rightRemote } = el.sceneEl.systems.interaction.state;
return leftHand.held === el || rightHand.held === el || rightRemote.held === el;
},

tick() {
const held = this.isHeld(this.el);
const isMine = this.el.components.networked && this.el.components.networked.data && NAF.utils.isMine(this.el);
const isHeld = this.el.sceneEl.systems.interaction.isHeld(this.el);
const isMine = this._isMine();

let didFireThisFrame = false;
if (!held && this.wasHeld && isMine) {
if (!isHeld && this.wasHeld && isMine) {
didFireThisFrame = true;
this._fireEventsAndAnimate({ oldData: this.data, force: true });
this._persistAndAnimate();
}

this.wasHeld = held;
this.wasHeld = isHeld;

this.transformObjectSystem = this.transformObjectSystem || AFRAME.scenes[0].systems["transform-selected-object"];
const transforming = this.transformObjectSystem.transforming && this.transformObjectSystem.target.el === this.el;
if (!didFireThisFrame && !transforming && this.wasTransforming && isMine) {
this._fireEventsAndAnimate({ oldData: this.data, force: true });
this._persistAndAnimate();
}
this.wasTransforming = transforming;
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/tools/networked-drawing.js
Original file line number Diff line number Diff line change
Expand Up @@ -764,7 +764,7 @@ AFRAME.registerComponent("deserialize-drawing-button", {
addMeshScaleAnimation(drawingManager.drawing.el.object3DMap.mesh, { x: 0.001, y: 0.001, z: 0.001 });

if (this.targetEl.components.pinnable && this.targetEl.components.pinnable.data.pinned) {
this.targetEl.setAttribute("pinnable", "pinned", false);
window.APP.pinningHelper.setPinned(this.targetEl, false);
}
this.targetEl.parentEl.removeChild(this.targetEl);
this.el.sceneEl.systems["hubs-systems"].soundEffectsSystem.playSoundOneShot(SOUND_PEN_START_DRAW);
Expand Down
3 changes: 3 additions & 0 deletions src/hub.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ import "./gltf-component-mappings";

import { App } from "./App";
import MediaDevicesManager from "./utils/media-devices-manager";
import PinningHelper from "./utils/pinning-helper";
import { sleep } from "./utils/async-utils";
import { platformUnsupported } from "./support";

Expand Down Expand Up @@ -804,6 +805,8 @@ document.addEventListener("DOMContentLoaded", async () => {
});
};

window.APP.pinningHelper = new PinningHelper(hubChannel, authChannel, store, performConditionalSignIn);

window.addEventListener("action_create_avatar", () => {
performConditionalSignIn(
() => hubChannel.signedIn,
Expand Down
6 changes: 2 additions & 4 deletions src/react-components/room/object-hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ export function usePinObject(hubChannel, scene, object) {
() => {
const el = object.el;
if (!NAF.utils.isMine(el) && !NAF.utils.takeOwnership(el)) return;
el.setAttribute("pinnable", "pinned", true);
el.emit("pinned", { el });
window.APP.pinningHelper.setPinned(el, true);
},
[object]
);
Expand All @@ -49,8 +48,7 @@ export function usePinObject(hubChannel, scene, object) {
() => {
const el = object.el;
if (!NAF.utils.isMine(el) && !NAF.utils.takeOwnership(el)) return;
el.setAttribute("pinnable", "pinned", false);
el.emit("unpinned", { el });
window.APP.pinningHelper.setPinned(el, false);
},
[object]
);
Expand Down
85 changes: 2 additions & 83 deletions src/scene-entry-manager.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import qsTruthy from "./utils/qs_truthy";
import nextTick from "./utils/next-tick";
import pinnedEntityToGltf from "./utils/pinned-entity-to-gltf";
import { hackyMobileSafariTest } from "./utils/detect-touchscreen";
import { isIOS as detectIOS } from "./utils/is-mobile";
import { SignInMessages } from "./react-components/auth/SignInModal";
Expand All @@ -12,7 +11,7 @@ const isMobileVR = AFRAME.utils.device.isMobileVR();
const isDebug = qsTruthy("debug");
const qs = new URLSearchParams(location.search);

import { addMedia, getPromotionTokenForFile } from "./utils/media-utils";
import { addMedia } from "./utils/media-utils";
import {
isIn2DInterstitial,
handleExitTo2DInterstitial,
Expand Down Expand Up @@ -189,7 +188,7 @@ export default class SceneEntryManager {

if (entity.components.networked.data.persistent) {
NAF.utils.takeOwnership(entity);
this._unpinElement(entity);
window.APP.pinningHelper.unpinElement(entity);
entity.parentNode.removeChild(entity);
} else {
NAF.entities.removeEntity(id);
Expand All @@ -208,74 +207,6 @@ export default class SceneEntryManager {
});
};

_pinElement = async el => {
const { networkId } = el.components.networked.data;

const { fileId, src } = el.components["media-loader"].data;

let fileAccessToken, promotionToken;
if (fileId) {
fileAccessToken = new URL(src).searchParams.get("token");
const storedPromotionToken = getPromotionTokenForFile(fileId);
if (storedPromotionToken) {
promotionToken = storedPromotionToken.promotionToken;
}
}

const gltfNode = pinnedEntityToGltf(el);
if (!gltfNode) return;
el.setAttribute("networked", { persistent: true });
el.setAttribute("media-loader", { fileIsOwned: true });

try {
await this.hubChannel.pin(networkId, gltfNode, fileId, fileAccessToken, promotionToken);
this.store.update({ activity: { hasPinned: true } });
} catch (e) {
if (e.reason === "invalid_token") {
await this.authChannel.signOut(this.hubChannel);
this._signInAndPinOrUnpinElement(el);
} else {
console.warn("Pin failed for unknown reason", e);
}
}
};

_signInAndPinOrUnpinElement = (el, pin) => {
const action = pin
? () => this._pinElement(el)
: async () => {
await this._unpinElement(el);
};

this.performConditionalSignIn(
() => this.hubChannel.signedIn,
action,
pin ? SignInMessages.pin : SignInMessages.unpin,
() => {
// UI pins/un-pins the entity optimistically, so we undo that here.
// Note we have to disable the sign in flow here otherwise this will recurse.
this._disableSignInOnPinAction = true;
el.setAttribute("pinnable", "pinned", !pin);
this._disableSignInOnPinAction = false;
}
);
};

_unpinElement = el => {
const components = el.components;
const networked = components.networked;

if (!networked || !networked.data || !NAF.utils.isMine(el)) return;

const networkId = components.networked.data.networkId;
el.setAttribute("networked", { persistent: false });

const mediaLoader = components["media-loader"];
const fileId = mediaLoader.data && mediaLoader.data.fileId;

this.hubChannel.unpin(networkId, fileId);
};

_setupMedia = () => {
const offset = { x: 0, y: 0, z: -1.5 };
const spawnMediaInfrontOfPlayer = (src, contentOrigin) => {
Expand Down Expand Up @@ -305,18 +236,6 @@ export default class SceneEntryManager {
spawnMediaInfrontOfPlayer(e.detail, contentOrigin);
});

const handlePinEvent = (e, pinned) => {
if (this._disableSignInOnPinAction) return;
const el = e.detail.el;

if (NAF.utils.isMine(el)) {
this._signInAndPinOrUnpinElement(e.detail.el, pinned);
}
};

this.scene.addEventListener("pinned", e => handlePinEvent(e, true));
this.scene.addEventListener("unpinned", e => handlePinEvent(e, false));

this.scene.addEventListener("object_spawned", e => {
this.hubChannel.sendObjectSpawnedEvent(e.detail.objectType);
});
Expand Down
2 changes: 1 addition & 1 deletion src/utils/media-url-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import configs from "./configs";

const nonCorsProxyDomains = (configs.NON_CORS_PROXY_DOMAINS || "").split(",");
if (configs.CORS_PROXY_SERVER) {
nonCorsProxyDomains.push(configs.CORS_PROXY_SERVER);
nonCorsProxyDomains.push(configs.CORS_PROXY_SERVER.split(":")[0]);
}
nonCorsProxyDomains.push(document.location.hostname);

Expand Down
Loading

0 comments on commit 86743cf

Please sign in to comment.