Skip to content

Commit

Permalink
Fix screenshot taking and screen recording in AR (#256)
Browse files Browse the repository at this point in the history
* Fix screenshot taking

Screenshot taking wasn't working due to a react "this" issue. In JavaScript,
class methods are not bound to the instance like an arrow function is.
So, when a user of ViroARSceneNavigator tries to use these functions,
the "this" instance didn't have all of the React properties that make
React Native's findNodeHandle work correctly.

Changing functions like:

async _takeScreenshot(fileName, saveToCameraRoll) {
  // ...
}

To

_takeScreenshot = (filename, saveToCameraRoll) => {
  // ...
}

Fixes the issue.

Also adds more documentation to the ViroARSceneNavigator.

* fix: add missing dist files
* chore: version bump 2.23.2
  • Loading branch information
robertjcolley authored Feb 10, 2024
1 parent b042cf0 commit eac9454
Show file tree
Hide file tree
Showing 10 changed files with 649 additions and 445 deletions.
395 changes: 226 additions & 169 deletions components/AR/ViroARSceneNavigator.tsx

Large diffs are not rendered by default.

29 changes: 14 additions & 15 deletions components/Viro3DSceneNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,19 +83,6 @@ type State = {
export class Viro3DSceneNavigator extends React.Component<Props, State> {
_component: ViroNativeRef = null;

sceneNavigator = {
push: this.push,
pop: this.pop,
popN: this.popN,
jump: this.jump,
replace: this.replace,
// exitViro: this.exitViro, TODO: this was unused
recenterTracking: this._recenterTracking,
project: this._project,
unproject: this._unproject,
viroAppProps: {} as any,
};

/**
* Called from native when either the user physically decides to exit vr (hits
* the "X" buton).
Expand Down Expand Up @@ -349,8 +336,7 @@ export class Viro3DSceneNavigator extends React.Component<Props, State> {
* (counts equals 0), we then remove that scene from sceneDictionary.
*/
decrementReferenceForLastNScenes(n: number) {
var sceneHistory = this.state.sceneHistory;
var sceneDictionary = this.state.sceneDictionary;
const { sceneHistory, sceneDictionary } = this.state;

// Now update and release any reference counts
for (var i = 1; i <= n; i++) {
Expand Down Expand Up @@ -473,6 +459,19 @@ export class Viro3DSceneNavigator extends React.Component<Props, State> {
);
}

sceneNavigator = {
push: this.push,
pop: this.pop,
popN: this.popN,
jump: this.jump,
replace: this.replace,
// exitViro: this.exitViro, TODO: this was unused
recenterTracking: this._recenterTracking,
project: this._project,
unproject: this._unproject,
viroAppProps: {} as any,
};

render() {
// Uncomment this line to check for misnamed props
//checkMisnamedProps("Viro3DSceneNavigator", this.props);
Expand Down
25 changes: 13 additions & 12 deletions components/ViroVRSceneNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,18 +84,6 @@ type Props = ViewProps & {
* ViroVRSceneNavigator is used to transition between multiple scenes.
*/
export class ViroVRSceneNavigator extends React.Component<Props, State> {
sceneNavigator = {
push: this.push,
pop: this.pop,
popN: this.popN,
jump: this.jump,
replace: this.replace,
// exitViro: this.exitViro, // not defined?
project: this._project,
unproject: this._unproject,
recenterTracking: this._recenterTracking,
viroAppProps: {} as any,
};
_component: ViroNativeRef = null;

/**
Expand Down Expand Up @@ -472,6 +460,19 @@ export class ViroVRSceneNavigator extends React.Component<Props, State> {
return views;
}

sceneNavigator = {
push: this.push,
pop: this.pop,
popN: this.popN,
jump: this.jump,
replace: this.replace,
// exitViro: this.exitViro, // not defined?
project: this._project,
unproject: this._unproject,
recenterTracking: this._recenterTracking,
viroAppProps: {} as any,
};

render() {
var items = this._renderSceneStackItems();

Expand Down
196 changes: 144 additions & 52 deletions dist/components/AR/ViroARSceneNavigator.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,38 +53,43 @@ type State = {
*/
export declare class ViroARSceneNavigator extends React.Component<Props, State> {
_component: ViroNativeRef;
arSceneNavigator: {
push: (param1?: ViroScene | string, param2?: ViroScene) => void;
pop: () => void;
popN: (n: number) => void;
jump: (param1?: ViroScene | string, param2?: ViroScene) => void;
replace: (param1?: ViroScene | string, param2?: ViroScene) => void;
startVideoRecording: (fileName: string, saveToCameraRoll: boolean, onError: (errorCode: number) => void) => void;
stopVideoRecording: () => Promise<any>;
takeScreenshot: (fileName: string, saveToCameraRoll: boolean) => Promise<any>;
resetARSession: (resetTracking: any, removeAnchors: any) => void;
setWorldOrigin: (worldOrigin: ViroWorldOrigin) => void;
project: (point: Viro3DPoint) => Promise<any>;
unproject: (point: Viro3DPoint) => Promise<any>;
viroAppProps: any;
};
sceneNavigator: {
push: (param1?: ViroScene | string, param2?: ViroScene) => void;
pop: () => void;
popN: (n: number) => void;
jump: (param1?: ViroScene | string, param2?: ViroScene) => void;
replace: (param1?: ViroScene | string, param2?: ViroScene) => void;
startVideoRecording: (fileName: string, saveToCameraRoll: boolean, onError: (errorCode: number) => void) => void;
stopVideoRecording: () => Promise<any>;
takeScreenshot: (fileName: string, saveToCameraRoll: boolean) => Promise<any>;
resetARSession: (resetTracking: any, removeAnchors: any) => void;
setWorldOrigin: (worldOrigin: ViroWorldOrigin) => void;
project: (point: Viro3DPoint) => Promise<any>;
unproject: (point: Viro3DPoint) => Promise<any>;
viroAppProps: any;
};
constructor(props: Props);
getRandomTag(): string;
/**
* Starts recording video of the Viro renderer and external audio
*
* @param fileName - name of the file (without extension)
* @param saveToCameraRoll - whether or not the file should also be saved to the camera roll
* @param onError - callback function that accepts an errorCode.
*/
_startVideoRecording: (fileName: string, saveToCameraRoll: boolean, onError: (errorCode: number) => void) => void;
/**
* Stops recording the video of the Viro Renderer.
*
* returns Object w/ success, url and errorCode keys.
* @returns Promise that resolves when the video has stopped recording.
*/
_stopVideoRecording: () => Promise<any>;
/**
* Takes a screenshot of the Viro renderer
*
* @param fileName - name of the file (without extension)
* @param saveToCameraRoll - whether or not the file should also be saved to the camera roll
* returns Object w/ success, url and errorCode keys.
*/
_takeScreenshot: (fileName: string, saveToCameraRoll: boolean) => Promise<any>;
/**
* @todo document _project
*
* @param point
* @returns
*/
_project(point: Viro3DPoint): Promise<any>;
/**
* Gets a random tag string.
*
* @returns a random tag.
*/
getRandomTag: () => string;
/**
* Pushes a scene and reference it with the given key if provided.
* If the scene has been previously pushed, we simply show the scene again.
Expand All @@ -97,9 +102,10 @@ export declare class ViroARSceneNavigator extends React.Component<Props, State>
* push ("sceneKey", scene);
* push (scene);
*
* @todo: use Typescript function overloading rather than this inaccurate solution
* @todo use Typescript function overloading rather than this inaccurate solution
* @todo document parameters
*/
push(param1?: ViroScene | string, param2?: ViroScene): void;
push: (param1?: ViroScene | string, param2?: ViroScene) => void;
/**
* Replace the top scene in the stack with the given scene. The remainder of the back
* history is kept in the same order as before.
Expand All @@ -109,9 +115,10 @@ export declare class ViroARSceneNavigator extends React.Component<Props, State>
* replace ("sceneKey", scene);
* replace (scene);
*
* @todo: use Typescript function overloading rather than this inaccurate solution
* @todo use Typescript function overloading rather than this inaccurate solution
* @todo document parameters
*/
replace(param1?: ViroScene | string, param2?: ViroScene): void;
replace: (param1?: ViroScene | string, param2?: ViroScene) => void;
/**
* Jumps to a given scene that had been previously pushed. If the scene was not pushed, we
* then push and jump to it. The back history is re-ordered such that jumped to scenes are
Expand All @@ -122,46 +129,131 @@ export declare class ViroARSceneNavigator extends React.Component<Props, State>
* jump ("sceneKey", scene);
* jump (scene);
*
* @todo: use Typescript function overloading rather than this inaccurate solution
* @todo use Typescript function overloading rather than this inaccurate solution
* @todo document parameters
*/
jump(param1?: ViroScene | string, param2?: ViroScene): void;
pop(): void;
popN(n: number): void;
jump: (param1?: ViroScene | string, param2?: ViroScene) => void;
/**
* Pop 1 screen from the stack.
*/
pop: () => void;
/**
* Pop n screens from the stack.
*
* @param n number of scenes to pop
* @returns void
*/
popN: (n: number) => void;
/**
* Increments the reference count for a scene within sceneDictionary that is
* mapped to the given sceneKey. If no scenes are found / mapped, we create
* one, initialize it with a reference count of 1, and store it within the
* sceneDictionary for future reference.
*
* @todo TODO: Document parameters.
*/
incrementSceneReference(scene: ViroScene, sceneKey: string, limitOne: boolean): void;
incrementSceneReference: (scene: ViroScene, sceneKey: string, limitOne: boolean) => void;
/**
* Decrements the reference count for the last N scenes within
* the sceneHistory by 1. If nothing else references that given scene
* (counts equals 0), we then remove that scene from sceneDictionary.
*
* @param n number to decrement by.
*/
decrementReferenceForLastNScenes(n: number): void;
decrementReferenceForLastNScenes: (n: number) => void;
/**
* Adds the given sceneKey to the sceneHistory and updates the currentSceneIndex to point
* to the scene on the top of the history stack (the most recent scene).
*
* @param sceneKey scene to insert into the stack.
*/
addToHistory(sceneKey: string): void;
addToHistory: (sceneKey: string) => void;
/**
* Instead of preserving history, we find the last pushed sceneKey within the history stack
* matching the given sceneKey and re-order it to the front. We then update the
* currentSceneIndex to point to the scene on the top of the history stack
* (the most recent scene).
*
* @param sceneKey scene to put at the top of the stack.
*/
reorderHistory: (sceneKey: string) => void;
/**
* Pops the history entries by n screens.
*
* @param n number of history entries to pop.
*/
reorderHistory(sceneKey: string): void;
popHistoryByN(n: number): void;
getSceneIndex(sceneTag: string): number;
_startVideoRecording(fileName: string, saveToCameraRoll: boolean, onError: (errorCode: number) => void): void;
_stopVideoRecording(): Promise<any>;
_takeScreenshot(fileName: string, saveToCameraRoll: boolean): Promise<any>;
_project(point: Viro3DPoint): Promise<any>;
_unproject(point: Viro3DPoint): Promise<any>;
_resetARSession(resetTracking: any, removeAnchors: any): void;
_setWorldOrigin(worldOrigin: ViroWorldOrigin): void;
_renderSceneStackItems(): JSX.Element[];
/**
* Gets the index of a scene by the scene tag.
*
* @param sceneTag tag of the scene
* @returns the index of the scene
*/
getSceneIndex: (sceneTag: string) => number;
/**
* TODO: Document _unproject
*
* @param point
* @returns
*/
_unproject: (point: Viro3DPoint) => Promise<any>;
/**
* [iOS Only]
*
* Resets the tracking of the AR session.
*
* @param resetTracking - determines if the tracking should be reset.
* @param removeAnchors - determines if the existing anchors should be removed too.
*/
_resetARSession: (resetTracking: any, removeAnchors: any) => void;
/**
* [iOS/ARKit 1.5+ Only]
*
* Allows the developer to offset the current world orgin
* by the given transformation matrix. ie. if this is called twice with the
* position [0, 0, 1], then current world origin will be at [0, 0, 2] from its
* initial position (it's additive, not meant to replace the existing origin)
*
* @param worldOrigin - a dictionary that can contain a `position` and `rotation` key with an
* array containing 3 floats (note: rotation is in degrees).
*/
_setWorldOrigin: (worldOrigin: ViroWorldOrigin) => void;
/**
* Renders the Scene Views in the stack.
*
* @returns Array of rendered Scene views.
*/
_renderSceneStackItems: () => JSX.Element[];
arSceneNavigator: {
push: (param1?: ViroScene | string, param2?: ViroScene) => void;
pop: () => void;
popN: (n: number) => void;
jump: (param1?: ViroScene | string, param2?: ViroScene) => void;
replace: (param1?: ViroScene | string, param2?: ViroScene) => void;
startVideoRecording: (fileName: string, saveToCameraRoll: boolean, onError: (errorCode: number) => void) => void;
stopVideoRecording: () => Promise<any>;
takeScreenshot: (fileName: string, saveToCameraRoll: boolean) => Promise<any>;
resetARSession: (resetTracking: any, removeAnchors: any) => void;
setWorldOrigin: (worldOrigin: ViroWorldOrigin) => void;
project: (point: Viro3DPoint) => Promise<any>;
unproject: (point: Viro3DPoint) => Promise<any>;
viroAppProps: any;
};
sceneNavigator: {
push: (param1?: ViroScene | string, param2?: ViroScene) => void;
pop: () => void;
popN: (n: number) => void;
jump: (param1?: ViroScene | string, param2?: ViroScene) => void;
replace: (param1?: ViroScene | string, param2?: ViroScene) => void;
startVideoRecording: (fileName: string, saveToCameraRoll: boolean, onError: (errorCode: number) => void) => void;
stopVideoRecording: () => Promise<any>;
takeScreenshot: (fileName: string, saveToCameraRoll: boolean) => Promise<any>;
resetARSession: (resetTracking: any, removeAnchors: any) => void;
setWorldOrigin: (worldOrigin: ViroWorldOrigin) => void;
project: (point: Viro3DPoint) => Promise<any>;
unproject: (point: Viro3DPoint) => Promise<any>;
viroAppProps: any;
};
render(): JSX.Element;
}
export {};
Loading

0 comments on commit eac9454

Please sign in to comment.