forked from MapComplete/MapComplete
		
	Add mapillary link to nearby_images Fix licenses Add missing assets First version of nearby-images
		
			
				
	
	
		
			133 lines
		
	
	
	
		
			4.5 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			133 lines
		
	
	
	
		
			4.5 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import Combine from "../Base/Combine";
 | |
| import {UIEventSource} from "../../Logic/UIEventSource";
 | |
| import {SlideShow} from "../Image/SlideShow";
 | |
| import Toggle from "../Input/Toggle";
 | |
| import Loading from "../Base/Loading";
 | |
| import {AttributedImage} from "../Image/AttributedImage";
 | |
| import AllImageProviders from "../../Logic/ImageProviders/AllImageProviders";
 | |
| import Svg from "../../Svg";
 | |
| import BaseUIElement from "../BaseUIElement";
 | |
| import {InputElement} from "../Input/InputElement";
 | |
| import {VariableUiElement} from "../Base/VariableUIElement";
 | |
| import Translations from "../i18n/Translations";
 | |
| import {Mapillary} from "../../Logic/ImageProviders/Mapillary";
 | |
| 
 | |
| export interface P4CPicture {
 | |
|     pictureUrl: string,
 | |
|     date: number,
 | |
|     coordinates: { lat: number, lng: number },
 | |
|     provider: "Mapillary" | string,
 | |
|     author,
 | |
|     license,
 | |
|     detailsUrl: string,
 | |
|     direction,
 | |
|     osmTags: object /*To copy straight into OSM!*/
 | |
|     ,
 | |
|     thumbUrl: string,
 | |
|     details: {
 | |
|         isSpherical: boolean,
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| interface NearbyImageOptions {
 | |
|     lon: number,
 | |
|     lat: number,
 | |
|     radius: number,
 | |
|     maxDaysOld?: 1095,
 | |
|     blacklist: UIEventSource<{url: string}[]>
 | |
| }
 | |
| 
 | |
| export default class NearbyImages extends VariableUiElement {
 | |
| 
 | |
|     constructor(options: NearbyImageOptions) {
 | |
|         const t = Translations.t.image.nearbyPictures
 | |
|         const P4C = require("../../vendor/P4C.min")
 | |
|         const picManager = new P4C.PicturesManager({});
 | |
| 
 | |
|         const loadedPictures = UIEventSource.FromPromise<P4CPicture[]>(
 | |
|             picManager.startPicsRetrievalAround(new P4C.LatLng(options.lat, options.lon), options.radius, {
 | |
|                 mindate: new Date().getTime() - (options.maxDaysOld ?? 1095) * 24 * 60 * 60 * 1000
 | |
|             })
 | |
|         ).map(images => {
 | |
|             console.log("Images are" ,images, "blacklisted is", options.blacklist.data)
 | |
|             images?.sort((a, b) => b.date - a.date)
 | |
|             return images ?.filter(i => !(options.blacklist?.data?.some(blacklisted => 
 | |
|                     Mapillary.sameUrl(i.pictureUrl, blacklisted.url)))
 | |
|                 && i.details.isSpherical === false);
 | |
|         }, [options.blacklist])
 | |
| 
 | |
|         super(loadedPictures.map(images => {
 | |
|             if(images === undefined){
 | |
|               return  new Loading(t.loading);
 | |
|             }
 | |
|             if(images.length === 0){
 | |
|                 return t.nothingFound.SetClass("alert block")
 | |
|             }
 | |
|             return new SlideShow(loadedPictures.map(imgs => (imgs ?? []).slice(0, 25).map(i => this.prepareElement(i))))
 | |
|         }));
 | |
|                
 | |
|     }
 | |
| 
 | |
|     protected prepareElement(info: P4CPicture): BaseUIElement {
 | |
|         const provider = AllImageProviders.byName(info.provider);
 | |
|         return new AttributedImage({url: info.pictureUrl, provider})
 | |
|     }
 | |
| 
 | |
|     private asAttributedImage(info: P4CPicture): AttributedImage {
 | |
|         const provider = AllImageProviders.byName(info.provider);
 | |
|         return new AttributedImage({url: info.thumbUrl, provider, date: new Date(info.date)})
 | |
|     }
 | |
|     
 | |
|     protected asToggle(info:P4CPicture): Toggle {
 | |
|         const imgNonSelected = this.asAttributedImage(info);
 | |
|         const imageSelected = this.asAttributedImage(info);
 | |
| 
 | |
|         const nonSelected = new Combine([imgNonSelected]).SetClass("relative block")
 | |
|         const hoveringCheckmark =
 | |
|             new Combine([Svg.confirm_svg().SetClass("block w-24 h-24 -ml-12 -mt-12")]).SetClass("absolute left-1/2 top-1/2 w-0")
 | |
|         const selected = new Combine([
 | |
|             imageSelected,
 | |
|             hoveringCheckmark,
 | |
|         ]).SetClass("relative block")
 | |
| 
 | |
|         return new Toggle(selected, nonSelected).SetClass("").ToggleOnClick();
 | |
| 
 | |
|     }
 | |
| 
 | |
| }
 | |
| 
 | |
| export class SelectOneNearbyImage extends NearbyImages implements InputElement<P4CPicture> {
 | |
|     private readonly value: UIEventSource<P4CPicture>;
 | |
| 
 | |
|     constructor(options: NearbyImageOptions & {value?: UIEventSource<P4CPicture>}) {
 | |
|         super(options)
 | |
|         this.value = options.value ?? new UIEventSource<P4CPicture>(undefined);
 | |
|     }
 | |
| 
 | |
|     GetValue(): UIEventSource<P4CPicture> {
 | |
|         return this.value;
 | |
|     }
 | |
| 
 | |
|     IsValid(t: P4CPicture): boolean {
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     protected prepareElement(info: P4CPicture): BaseUIElement {
 | |
|         const toggle = super.asToggle(info)
 | |
|         toggle.isEnabled.addCallback(enabled => {
 | |
|             if (enabled) {
 | |
|                 this.value.setData(info)
 | |
|             }
 | |
|         })
 | |
| 
 | |
|         this.value.addCallback(inf => {
 | |
|             if(inf !== info){
 | |
|                 toggle.isEnabled.setData(false)
 | |
|             }
 | |
|         })
 | |
| 
 | |
|         return toggle
 | |
|     }
 | |
| 
 | |
| }
 |