Skip to content

Commit

Permalink
Delete favorite option for gadgets
Browse files Browse the repository at this point in the history
* Added a menu to the A button when hovering over a moveable. Currently only gadget seeds in the favorites tab actually implement a menu, but they could be added to anything.
* Added a "remove favorite" menu option to the menu for favorite gadget seeds.
* added remove favorite to the gadget list interface and the default landing page.

Fixes #52
  • Loading branch information
JoeLudwig committed Sep 5, 2020
1 parent 7c9fa41 commit 01e093b
Show file tree
Hide file tree
Showing 9 changed files with 593 additions and 172 deletions.
29 changes: 26 additions & 3 deletions packages/aardvark-react/src/aardvark_gadget_seed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export enum GadgetSeedHighlight
Idle,
GrabberNearby,
GadgetStarting,
Menu,
}


Expand Down Expand Up @@ -76,6 +77,7 @@ enum GadgetSeedPhase
WaitingForGadgetStart,
WaitingForRegrab,
WaitingForRedropToFinish,
Menu,
}

interface AvGadgetSeedState
Expand Down Expand Up @@ -278,6 +280,9 @@ export class AvGadgetSeed extends React.Component< AvGadgetSeedProps, AvGadgetSe
case GadgetSeedPhase.WaitingForRedropToFinish:
case GadgetSeedPhase.WaitingForRegrab:
return GadgetSeedHighlight.GadgetStarting;

case GadgetSeedPhase.Menu:
return GadgetSeedHighlight.Menu;
}
}

Expand All @@ -293,19 +298,33 @@ export class AvGadgetSeed extends React.Component< AvGadgetSeedProps, AvGadgetSe
}
}

componentWillUnmount()
{
if( this.state.phase != GadgetSeedPhase.Idle )
{
this.props.highlightCallback?.( GadgetSeedHighlight.Idle );
}
}


@bind
private async onMoveableUpdate()
{
switch( this.state.phase )
{
case GadgetSeedPhase.Idle:
if( this.moveableComponent.state == MoveableComponentState.GrabberNearby)
switch( this.moveableComponent.state )
{
this.setState( { phase: GadgetSeedPhase.GrabberNearby } );
case MoveableComponentState.GrabberNearby:
this.setState( { phase: GadgetSeedPhase.GrabberNearby } );
break;
case MoveableComponentState.Menu:
this.setState( { phase: GadgetSeedPhase.Menu } );
break;
}
break;

case GadgetSeedPhase.Menu:
case GadgetSeedPhase.GrabberNearby:
switch( this.moveableComponent.state )
{
Expand All @@ -319,12 +338,16 @@ export class AvGadgetSeed extends React.Component< AvGadgetSeedProps, AvGadgetSe
break;

case MoveableComponentState.GrabberNearby:
// do nothing. We're already in the right state
this.setState( { phase: GadgetSeedPhase.GrabberNearby } );
break;

case MoveableComponentState.InContainer:
// This means we missed the grab and were already dropped?
break;

case MoveableComponentState.Menu:
this.setState( { phase: GadgetSeedPhase.Menu } );
break;
}
break;

Expand Down
128 changes: 128 additions & 0 deletions packages/aardvark-react/src/aardvark_menu_item.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import { AvVolume, EVolumeType, AvColor } from '@aardvarkxr/aardvark-shared';
import bind from 'bind-decorator';
import * as React from 'react';
import { ActiveInterface, AvInterfaceEntity } from './aardvark_interface_entity';
import { AvModel } from './aardvark_model';
import { PanelRequest, PanelRequestType } from './aardvark_panel';
import { AvTransform } from './aardvark_transform';


/** Props for {@link AvMenuItem} */
export interface MenuItemProps
{
/** The onSelect callback is called when the menu button is released while on the menu item. */
onSelect?: () => void;

/** The onHighlight callback is called when the menu item is touched by the grabber (and will
* be selected if the user releases the menu button.) */
onHighlight?: () => void;

/** The URI of the GLTF model to use for this grab button. Exactly one
* of modelUri and radius must be specified. If modelUri is specified,
* the bounding box of the model will also be used as the grabbable
* region for the button.
*/
modelUri?: string;

/** The color to apply to the model.
*
* @default none
*/
color?: string | AvColor;

/** The radius of the sphere that defines the grabbable handle for this
* grab button. Exactly one of modelUri and radius must be specified.
*/
radius?: number;
}

interface MenuItemState
{
menuCount: number;
}

export const k_MenuInterface = "aardvark-menu@1";

export enum MenuEventType
{
Activate = "activate",
}

export interface MenuEvent
{
type: MenuEventType;
}


/** A component that signals when it is grabbed. */
export class AvMenuItem extends React.Component< MenuItemProps, MenuItemState >
{
constructor( props: any )
{
super( props );

this.state =
{
menuCount: 0,
};
}

@bind
private onMenu( activeMenu: ActiveInterface )
{
if( this.state.menuCount == 0 )
{
this.props.onHighlight?.();
}

this.setState( ( prevState ) => { return { menuCount: prevState.menuCount + 1 }; } );

activeMenu.onEvent( ( event: MenuEvent ) =>
{
switch( event.type )
{
case MenuEventType.Activate:
this.props.onSelect?.();
break;
}
} );

activeMenu.onEnded( () =>
{
this.setState( ( prevState ) => { return { menuCount: prevState.menuCount - 1 }; } );
})
}

public render()
{
let scale = ( this.state.menuCount > 0 ) ? 1.1 : 1.0;
let volume: AvVolume;
if( this.props.radius )
{
volume =
{
type: EVolumeType.Sphere,
radius: this.props.radius,
};
}
else if( this.props.modelUri )
{
volume =
{
type: EVolumeType.ModelBox,
uri: this.props.modelUri,
};
}

return <>
<AvTransform uniformScale={ scale }>
{ this.props.modelUri && <AvModel uri={ this.props.modelUri }
color={ this.props.color }/> }
{ this.props.children }
</AvTransform>
<AvInterfaceEntity volume={ volume } priority={ 20 }
receives={ [ { iface: k_MenuInterface, processor: this.onMenu } ] }/>
</>;
}
}

11 changes: 11 additions & 0 deletions packages/aardvark-react/src/api_gadgetlist.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const k_GadgetListInterface = "api-gadgetlist@1";
export enum GadgetListEventType
{
AddFavorite = "add_favorite",
RemoveFavorite = "remove_favorite",
StartGadget = "start_gadget",
}

Expand All @@ -17,6 +18,7 @@ export enum GadgetListResult
UserDeniedRequest = 2,
NotConnected = 3,
GadgetStartFailed = 4,
NoSuchFavorite = 5,
}


Expand All @@ -35,6 +37,15 @@ export class AvGadgetList extends React.Component
GadgetListEventType.AddFavorite, true, gadgetUrl );
}

public removeFavorite( gadgetUrl: string )
{
if( !this.apiInterface.current || !this.apiInterface.current.connected )
return GadgetListResult.NotConnected;

return this.apiInterface.current.sendRequestAndWaitForResponse<GadgetListResult>(
GadgetListEventType.RemoveFavorite, true, gadgetUrl );
}

public startGadget( gadgetUrl: string )
{
if( !this.apiInterface.current || !this.apiInterface.current.connected )
Expand Down
23 changes: 22 additions & 1 deletion packages/aardvark-react/src/component_moveable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export enum MoveableComponentState
InContainer,
GrabberNearby,
Grabbed,
Menu,
}

export enum ContainerRequestType
Expand All @@ -34,6 +35,8 @@ export enum GrabRequestType
ReleaseMe = "release_me",
RequestRegrab = "request_regrab",
OverrideTransform = "override_transform",
ShowMenu = "show_menu",
HideMenu = "hide_menu",
}

export interface GrabRequest
Expand Down Expand Up @@ -62,6 +65,7 @@ export class MoveableComponent implements EntityComponent
private waitingForRedropTransform: AvNodeTransform = null;
private canDropIntoContainers = true;
private forcedGrabberFromGrabbable: AvNodeTransform = null;
private shouldShowMenu = false;

constructor( callback: () => void, useInitialParent?: boolean, canDropIntoContainers?: boolean,
forcedGrabberFromGrabbable?: AvNodeTransform )
Expand Down Expand Up @@ -92,7 +96,14 @@ export class MoveableComponent implements EntityComponent
}
else if( this.activeGrabs.size > 0 )
{
return MoveableComponentState.GrabberNearby;
if( this.shouldShowMenu )
{
return MoveableComponentState.Menu;
}
else
{
return MoveableComponentState.GrabberNearby;
}
}
else if( this.activeContainer && this.wasEverDropped )
{
Expand Down Expand Up @@ -151,6 +162,16 @@ export class MoveableComponent implements EntityComponent
await this.dropIntoContainer( true );
activeGrab.sendEvent( { type: GrabRequestType.DropComplete } as GrabRequest );
break;

case GrabRequestType.ShowMenu:
this.shouldShowMenu = true;
this.updateListener();
break;

case GrabRequestType.HideMenu:
this.shouldShowMenu = false;
this.updateListener();
break;
}
} );

Expand Down
Loading

0 comments on commit 01e093b

Please sign in to comment.