diff --git a/src/imageadder.tsx b/src/imageadder.tsx index a15d06d..9eb46f0 100644 --- a/src/imageadder.tsx +++ b/src/imageadder.tsx @@ -5,7 +5,7 @@ import Dropzone from 'react-dropzone'; interface ImageAddedProps { - addImageCallback: ( url: string ) => void; + addImageCallback: ( url: string, remoteUrl: string ) => void; validateUrlCallback: ( url: string ) => boolean; } @@ -48,7 +48,8 @@ export class ImageAdder extends React.Component< ImageAddedProps, ImageAdderStat { if (this.props.validateUrlCallback(this.state.url)) { - this.props.addImageCallback( this.state.url ); + // use the same URL for both ends for hosted images + this.props.addImageCallback( this.state.url, this.state.url ); event.preventDefault(); } else @@ -65,11 +66,12 @@ export class ImageAdder extends React.Component< ImageAddedProps, ImageAdderStat { let res = await this.ipfsNode.add( new Uint8Array( result ) ); - const url = "/ipfs/" + res.cid; + // Use a hosted URL for the remote end + const url = "https://ipfs.io/ipfs/" + res.cid; console.log( `Adding ${ file.name } as ${ url }` ); const blobData: ArrayBuffer[] = [result]; const imageBlob = new Blob(blobData); - this.props.addImageCallback( URL.createObjectURL(imageBlob) ); + this.props.addImageCallback( URL.createObjectURL(imageBlob), url ); //this.props.addImageCallback("https://ipfs.io/ipfs/" + res.cid) <- this system is more efficient but slower as it relies on waiting for a return from the ipfs server and that server gets alot of requests } diff --git a/src/main.tsx b/src/main.tsx index 321378a..cec3a5a 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -20,20 +20,43 @@ class MenuItem extends React.Component< {displayImage, onClick, deleteSelfCallba - + { !AvGadget.instance().isRemote && + } ); } } -interface ImageMenuState +interface ImageMenuEntry { - imageUrls: string[]; + localUrl: string; + remoteUrl: string; } -class ImageMenu extends React.Component< {}, ImageMenuState> //class for the whole menu, basically just renders MenuItems according to list of images +enum ImageMenuEventType { - imageToDisplay: string; + SetImage = "set_image", +} + +interface ImageMenuEvent +{ + type: ImageMenuEventType; + url: string; +} + +interface ImageMenuState +{ + imageUrls: ImageMenuEntry[]; +} + +interface ImageMenuProps +{ + sendEventCallback: ( event: ImageMenuEvent ) => void; +} + +class ImageMenu extends React.Component< ImageMenuProps, ImageMenuState> //class for the whole menu, basically just renders MenuItems according to list of images +{ + imageToDisplay: ImageMenuEntry = null; constructor(props) { @@ -43,31 +66,48 @@ class ImageMenu extends React.Component< {}, ImageMenuState> //class for the who { imageUrls: [], } - - this.imageToDisplay = ""; } @bind - public onAddImage( url: string ) + public onAddImage( localUrl: string, remoteUrl: string ) { this.setState( { - imageUrls: [ ...this.state.imageUrls, url] + imageUrls: + [ + ...this.state.imageUrls, + { + localUrl, + remoteUrl, + } + ] } ); } @bind - public validateUrl(url:string) + public validateUrl( localUrl: string ) { - return(url && !this.state.imageUrls.includes(url) ? true : false) + return localUrl && this.findImageIndex( localUrl ) == -1; } - public displayImage(image: string) //given to buttons, by setting the image to display we stop drawing the menu and start drawing the image, remove image undoes this, we also force an update here since we dont use state + private findImageIndex( localUrl: string ) + { + return this.state.imageUrls.findIndex( ( value: ImageMenuEntry ) => value.localUrl == localUrl ); + } + + public displayImage( image: ImageMenuEntry ) //given to buttons, by setting the image to display we stop drawing the menu and start drawing the image, remove image undoes this, we also force an update here since we dont use state { this.imageToDisplay = image; this.forceUpdate(); + + this.props.sendEventCallback( + { + type: ImageMenuEventType.SetImage, + url: image.remoteUrl, + } + ); } public removeImage() @@ -76,20 +116,26 @@ class ImageMenu extends React.Component< {}, ImageMenuState> //class for the who this.forceUpdate(); } - public deleteListItem(item: string) + public deleteListItem(localUrl: string) { - this.state.imageUrls.splice(this.state.imageUrls.indexOf(item), 1); - this.forceUpdate(); + let i = this.findImageIndex( localUrl ); + if( i != -1 ) + { + this.state.imageUrls.splice( i, 1); + this.forceUpdate(); + } } public render() { if (this.imageToDisplay){ //if theres an image then show that, and also a back button + const url = AvGadget.instance().isRemote ? this.imageToDisplay.remoteUrl : this.imageToDisplay.localUrl; + return(
- +
) @@ -104,7 +150,7 @@ class ImageMenu extends React.Component< {}, ImageMenuState> //class for the who }; return(
- this.displayImage(image)} deleteSelfCallback = {() => this.deleteListItem(image)}/> + this.displayImage(image)} deleteSelfCallback = {() => this.deleteListItem( image.localUrl )}/>
); }); @@ -149,15 +195,25 @@ const k_popupHtml = `; +interface MyGadgetState +{ + remoteUrl: string; +} -class MyGadget extends React.Component< {}, {} > +class MyGadget extends React.Component< {}, MyGadgetState > { private addImagePopup: Window = null; private imageMenuRef = React.createRef(); + private grabbableRef = React.createRef(); constructor( props: any ) { super( props ); + + this.state = + { + remoteUrl: null, + } } public openWindow(){ @@ -168,24 +224,100 @@ class MyGadget extends React.Component< {}, {} > this.addImagePopup.document.getElementById( "root" ) ); } + @bind + private onRemoteEvent( event: ImageMenuEvent ) + { + switch( event.type ) + { + case ImageMenuEventType.SetImage: + { + this.setState( { remoteUrl: event.url } ); + } + break; + } + } - public render() + private renderLocal() { return (
- +
- + + { this.grabbableRef.current?.sendRemoteEvent( event, true ); } }/>
); } + private renderRemoteImage() + { + if (this.state.remoteUrl) + { + //if theres an image then show that + return( +
+
+ +
+
+ ) + } + else + { + return( +
+ The owner hasn't selected an image. +
+ ); + } + } + + private renderRemote() + { + + return ( +
+
+ + + + + + { this.renderRemoteImage() } +
+
); + + } + + public render() + { + if( AvGadget.instance().isRemote ) + { + return this.renderRemote(); + } + else + { + return this.renderLocal(); + } + } + } renderAardvarkRoot( "root", );