Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

save changes #900

Merged
merged 10 commits into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
</head>

<body>
<img id="screenshot-img" src="ui_assets/3DStreet-Viewer-Start-Editor.svg" alt="Invisible Image" style="display:none;">
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

created an invisible image so that the screentock functions can be synchronous

<!-- loading animation start -->
<div class="loader__wrapper">
<div class="loader">
Expand All @@ -47,7 +48,6 @@
<div class="road">Loading 3DStreet</div>
</div>
</div>

<!-- viewer ui start -->
<div class="viewer-header-wrapper">
<button class="viewer-logo-start-editor-button" onclick="startEditor()">
Expand Down
28 changes: 7 additions & 21 deletions src/components/screentock.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ AFRAME.registerComponent('screentock', {
type: { type: 'string', default: 'jpg' }, // png, jpg, img
imgElementSelector: { type: 'selector' }
},
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed all the async code from here

takeScreenshotNow: async function (filename, type, imgElement) {
takeScreenshotNow: function (filename, type, imgElement) {
const inspector = AFRAME.INSPECTOR;
const renderer = AFRAME.scenes[0].renderer;

Expand All @@ -32,7 +32,7 @@ AFRAME.registerComponent('screentock', {
if (inspector && inspector.opened) inspector.sceneHelpers.visible = show;
}

const createCanvasWithScreenshot = async (aframeCanvas) => {
const createCanvasWithScreenshot = (aframeCanvas) => {
let screenshotCanvas = document.querySelector('#screenshotCanvas');
if (!screenshotCanvas) {
screenshotCanvas = document.createElement('canvas');
Expand All @@ -53,7 +53,7 @@ AFRAME.registerComponent('screentock', {
screenshotCanvas.height
);
// add 3DStreet logo
await addLogoToCanvas(ctxScreenshot);
addLogoToCanvas(ctxScreenshot);
return screenshotCanvas;
};

Expand All @@ -68,21 +68,9 @@ AFRAME.registerComponent('screentock', {
);
}

const addLogoToCanvas = async (ctx) => {
const logoImg = document.querySelector('img.viewer-logo-img');
const logoSVG = document.querySelector('#aframeInspector #logoImg svg');

if (logoImg) {
ctx.drawImage(logoImg, 0, 0, 135, 43, 40, 30, 270, 86);
} else if (logoSVG) {
const image = new Image();
image.src = `data:image/svg+xml;base64,${window.btoa(logoSVG.outerHTML)}`;
await new Promise((resolve) => {
image.onload = resolve;
});

ctx.drawImage(image, 0, 0, 135, 23, 40, 40, 270, 46);
}
const addLogoToCanvas = (ctx) => {
const logoImg = document.querySelector('#screenshot-img');
ctx.drawImage(logoImg, 0, 0, 135, 43, 40, 30, 270, 86);
};

function downloadImageDataURL(filename, dataURL, scnrenshotCanvas) {
Expand All @@ -103,9 +91,7 @@ AFRAME.registerComponent('screentock', {

// render one frame
renderer.render(AFRAME.scenes[0].object3D, AFRAME.scenes[0].camera);
const screenshotCanvas = await createCanvasWithScreenshot(
renderer.domElement
);
const screenshotCanvas = createCanvasWithScreenshot(renderer.domElement);

if (type === 'img') {
imgElement.src = screenshotCanvas.toDataURL();
Expand Down
1 change: 0 additions & 1 deletion src/editor/api/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
export {
getUserScenes,
updateScene,
isSceneAuthor,
getCommunityScenes,
checkIfImagePathIsEmpty
} from './scene';
Expand Down
177 changes: 130 additions & 47 deletions src/editor/api/scene.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,17 @@ import {
where
} from 'firebase/firestore';
import { v4 as uuidv4 } from 'uuid';
import { db } from '../services/firebase';
import { db, storage } from '../services/firebase';
import { getDownloadURL, ref, uploadBytes } from 'firebase/storage';
import posthog from 'posthog-js';

const generateSceneId = async (authorId) => {
const userScenesRef = collection(db, 'scenes');
const sceneRef = collection(db, 'scenes');

const generateSceneId = async (authorId) => {
// Generate a new UUID
const newSceneId = uuidv4();

const newSceneDocRef = doc(userScenesRef, newSceneId);
const newSceneDocRef = doc(sceneRef, newSceneId);

// Use setDoc to set data on the specified document
await setDoc(newSceneDocRef, {
Expand All @@ -34,6 +36,22 @@ const generateSceneId = async (authorId) => {
return newSceneId;
};

const createScene = async (authorId, sceneData, title, version) => {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added a createScene

// Generate a new UUID
const newSceneId = uuidv4();
const newSceneDocRef = doc(sceneRef, newSceneId);

await setDoc(newSceneDocRef, {
createTimestamp: serverTimestamp(),
updateTimestamp: serverTimestamp(),
author: authorId,
data: sceneData,
title: title,
version: version
});
return newSceneId;
};

const deleteScene = async (sceneId) => {
try {
const sceneDocRef = doc(db, 'scenes', sceneId);
Expand All @@ -44,33 +62,23 @@ const deleteScene = async (sceneId) => {
}
};

const updateScene = async (sceneId, userUID, sceneData, title, version) => {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to pass user id in updating a scene

const updateScene = async (sceneId, sceneData, title, version) => {
try {
const userScenesRef = collection(db, 'scenes');
const sceneDocRef = doc(userScenesRef, sceneId);

const sceneSnapshot = await getDoc(sceneDocRef);
if (sceneSnapshot.exists()) {
await updateDoc(sceneDocRef, {
data: sceneData,
updateTimestamp: serverTimestamp(),
title: title,
version: version,
author: userUID
});
console.log('Firebase updateDoc fired');
} else {
throw new Error('No existing sceneSnapshot exists.');
}
const sceneDocRef = doc(sceneRef, sceneId);
await updateDoc(sceneDocRef, {
data: sceneData,
updateTimestamp: serverTimestamp(),
title: title,
version: version
});
} catch (error) {
throw new Error(error);
}
};

const updateSceneIdAndTitle = async (sceneId, title) => {
try {
const userScenesRef = collection(db, 'scenes');
const sceneDocRef = doc(userScenesRef, sceneId);
const sceneDocRef = doc(sceneRef, sceneId);

const sceneSnapshot = await getDoc(sceneDocRef);
if (sceneSnapshot.exists()) {
Expand All @@ -88,28 +96,6 @@ const updateSceneIdAndTitle = async (sceneId, title) => {
}
};

const isSceneAuthor = async ({ sceneId, authorId }) => {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no longer needed

if (!sceneId || !authorId) {
console.log('sceneId or authorId is not provided in isSceneAuthor');
return false;
}
try {
// Get a reference to the scene document
const sceneRef = doc(db, 'scenes', sceneId);
const sceneSnapshot = await getDoc(sceneRef);

if (sceneSnapshot.exists()) {
return sceneSnapshot.data().author === authorId;
} else {
console.error('Scene not found while running isSceneAuthor');
return false;
}
} catch (error) {
console.error('Error fetching scene while running isSceneAuthor:', error);
throw new Error('Error checking scene authorship');
}
};

let scenesSnapshot;
const getUserScenes = async (currentUserUID, isInitialFetch) => {
try {
Expand Down Expand Up @@ -189,13 +175,110 @@ const checkIfImagePathIsEmpty = async (sceneId) => {
}
};

const saveScreenshot = async (value) => {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved screenshot functionality to the scene api file so that the toolbar component didn't call functions from the screenshotmodalcomponent

const screenshotEl = document.getElementById('screenshot');
screenshotEl.play();

if (value === 'img') {
screenshotEl.setAttribute(
'screentock',
'imgElementSelector',
'#screentock-destination'
);
}

posthog.capture('screenshot_taken', {
type: value,
scene_id: STREET.utils.getCurrentSceneId()
});

screenshotEl.setAttribute('screentock', 'type', value);
screenshotEl.setAttribute('screentock', 'takeScreenshot', true);
};

const uploadThumbnailImage = async () => {
try {
// saveScreenshot('img');
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note, i commented this out, since in every call makeScreenshot is called prior


const screentockImgElement = document.getElementById(
'screentock-destination'
);

// Get the original image dimensions
const originalWidth = screentockImgElement.naturalWidth;
const originalHeight = screentockImgElement.naturalHeight;

// Define the target dimensions
const targetWidth = 320;
const targetHeight = 240;

// Calculate the scale factors
const scaleX = targetWidth / originalWidth;
const scaleY = targetHeight / originalHeight;

// Use the larger scale factor to fill the entire space
const scale = Math.max(scaleX, scaleY);

// Calculate the new dimensions
const newWidth = originalWidth * scale;
const newHeight = originalHeight * scale;

const resizedCanvas = document.createElement('canvas');
resizedCanvas.width = targetWidth;
resizedCanvas.height = targetHeight;
const context = resizedCanvas.getContext('2d');

// Calculate the position to center the image
const posX = (targetWidth - newWidth) / 2;
const posY = (targetHeight - newHeight) / 2;

// Draw the image on the canvas with the new dimensions and position
context.drawImage(screentockImgElement, posX, posY, newWidth, newHeight);
// Rest of the code...
const thumbnailDataUrl = resizedCanvas.toDataURL('image/jpeg', 0.5);
const blobFile = await fetch(thumbnailDataUrl).then((res) => res.blob());

const sceneDocId = STREET.utils.getCurrentSceneId();

const thumbnailRef = ref(storage, `scenes/${sceneDocId}/files/preview.jpg`);

const uploadedImg = await uploadBytes(thumbnailRef, blobFile);

const downloadURL = await getDownloadURL(uploadedImg.ref);
const userScenesRef = collection(db, 'scenes');
const sceneDocRef = doc(userScenesRef, sceneDocId);
const sceneSnapshot = await getDoc(sceneDocRef);
if (sceneSnapshot.exists()) {
await updateDoc(sceneDocRef, {
imagePath: downloadURL,
updateTimestamp: serverTimestamp()
});
console.log('Firebase updateDoc fired');
} else {
throw new Error('No existing sceneSnapshot exists.');
}

console.log('Thumbnail uploaded and Firestore updated successfully.');
} catch (error) {
console.error('Error capturing screenshot and updating Firestore:', error);
let errorMessage = `Error updating scene thumbnail: ${error}`;
if (error.code === 'storage/unauthorized') {
errorMessage =
'Error updating scene thumbnail: only the scene author may change the scene thumbnail. Save this scene as your own to change the thumbnail.';
STREET.notify.errorMessage(errorMessage);
}
}
};

export {
checkIfImagePathIsEmpty,
createScene,
deleteScene,
generateSceneId,
getCommunityScenes,
getUserScenes,
isSceneAuthor,
updateScene,
updateSceneIdAndTitle
updateSceneIdAndTitle,
uploadThumbnailImage,
saveScreenshot
};
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useEffect, useState } from 'react';
import styles from './SceneEditTitle.module.scss';
import { useAuthContext } from '../../../contexts/index.js';
import { updateSceneIdAndTitle, isSceneAuthor } from '../../../api/scene';
import { updateSceneIdAndTitle } from '../../../api/scene';

const SceneEditTitle = ({ sceneData }) => {
const [title, setTitle] = useState(sceneData?.sceneTitle);
Expand Down Expand Up @@ -35,11 +35,7 @@ const SceneEditTitle = ({ sceneData }) => {
const saveNewTitle = async (newTitle) => {
try {
if (sceneData?.sceneId) {
const isCurrentUserTheSceneAuthor = await isSceneAuthor({
sceneId: sceneData.sceneId,
authorId: currentUser.uid
});
if (isCurrentUserTheSceneAuthor) {
if (currentUser.uid === STREET.utils.getAuthorId()) {
await updateSceneIdAndTitle(sceneData?.sceneId, newTitle);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,9 @@ const ScenesModal = ({ isOpen, onClose, initialTab = 'owner', delay }) => {

const sceneId = scene.id;
const sceneTitle = sceneData.title;

AFRAME.scenes[0].setAttribute('metadata', 'sceneId', sceneId);
AFRAME.scenes[0].setAttribute('metadata', 'sceneTitle', sceneTitle);

AFRAME.scenes[0].setAttribute('metadata', 'authorId', sceneData.author);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when a new scene is loaded, set the authorId

STREET.notify.successMessage('Scene loaded from 3DStreet Cloud.');
onClose();
}
Expand Down
Loading