2023-09-20 01:47:32 +02:00
|
|
|
<script lang="ts">
|
2023-09-28 23:50:27 +02:00
|
|
|
import Translations from "../i18n/Translations"
|
|
|
|
import Tr from "../Base/Tr.svelte"
|
|
|
|
import PlantNetSpeciesList from "./PlantNetSpeciesList.svelte"
|
|
|
|
import { ImmutableStore, Store, UIEventSource } from "../../Logic/UIEventSource"
|
|
|
|
import type { PlantNetSpeciesMatch } from "../../Logic/Web/PlantNet"
|
|
|
|
import PlantNet from "../../Logic/Web/PlantNet"
|
|
|
|
import { XCircleIcon } from "@babeard/svelte-heroicons/solid"
|
|
|
|
import BackButton from "../Base/BackButton.svelte"
|
|
|
|
import NextButton from "../Base/NextButton.svelte"
|
|
|
|
import WikipediaPanel from "../Wikipedia/WikipediaPanel.svelte"
|
|
|
|
import { createEventDispatcher } from "svelte"
|
|
|
|
import ToSvelte from "../Base/ToSvelte.svelte"
|
|
|
|
import Svg from "../../Svg"
|
2023-09-20 01:47:32 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The main entry point for the plantnet wizard
|
|
|
|
*/
|
2023-09-28 23:50:27 +02:00
|
|
|
const t = Translations.t.plantDetection
|
2023-09-20 01:47:32 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* All the URLs pointing to images of the selected feature.
|
|
|
|
* We need to feed them into Plantnet when applicable
|
|
|
|
*/
|
2023-09-28 23:50:27 +02:00
|
|
|
export let imageUrls: Store<string[]>
|
|
|
|
export let onConfirm: (wikidataId: string) => void
|
|
|
|
const dispatch = createEventDispatcher<{ selected: string }>()
|
|
|
|
let collapsedMode = true
|
|
|
|
let options: UIEventSource<PlantNetSpeciesMatch[]> = new UIEventSource<PlantNetSpeciesMatch[]>(
|
|
|
|
undefined
|
|
|
|
)
|
2023-09-20 01:47:32 +02:00
|
|
|
|
2023-09-28 23:50:27 +02:00
|
|
|
let error: string = undefined
|
2023-09-20 01:47:32 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The Wikidata-id of the species to apply
|
|
|
|
*/
|
2023-09-28 23:50:27 +02:00
|
|
|
let selectedOption: string
|
2023-09-20 01:47:32 +02:00
|
|
|
|
2023-09-28 23:50:27 +02:00
|
|
|
let done = false
|
2023-09-20 01:47:32 +02:00
|
|
|
|
|
|
|
function speciesSelected(species: PlantNetSpeciesMatch) {
|
2023-09-28 23:50:27 +02:00
|
|
|
console.log("Selected:", species)
|
|
|
|
selectedOption = species
|
2023-09-20 01:47:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
async function detectSpecies() {
|
2023-09-28 23:50:27 +02:00
|
|
|
collapsedMode = false
|
2023-09-20 01:47:32 +02:00
|
|
|
|
|
|
|
try {
|
2023-09-28 23:50:27 +02:00
|
|
|
const result = await PlantNet.query(imageUrls.data.slice(0, 5))
|
|
|
|
options.set(result.results.filter((r) => r.score > 0.005).slice(0, 8))
|
2023-09-20 01:47:32 +02:00
|
|
|
} catch (e) {
|
2023-09-28 23:50:27 +02:00
|
|
|
error = e
|
2023-09-20 01:47:32 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<div class="flex flex-col">
|
|
|
|
{#if collapsedMode}
|
|
|
|
<button class="w-full" on:click={detectSpecies}>
|
|
|
|
<Tr t={t.button} />
|
|
|
|
</button>
|
|
|
|
{:else if $error !== undefined}
|
2023-09-28 23:50:27 +02:00
|
|
|
<Tr cls="alert" t={t.error.Subs({ error })} />
|
2023-09-20 01:47:32 +02:00
|
|
|
{:else if $imageUrls.length === 0}
|
|
|
|
<!-- No urls are available, show the explanation instead-->
|
2023-09-28 23:50:27 +02:00
|
|
|
<div class=" border-region relative mb-1 p-2">
|
|
|
|
<XCircleIcon
|
|
|
|
class="absolute top-0 right-0 m-4 h-8 w-8 cursor-pointer"
|
|
|
|
on:click={() => {
|
|
|
|
collapsedMode = true
|
|
|
|
}}
|
|
|
|
/>
|
2023-09-20 01:47:32 +02:00
|
|
|
<Tr t={t.takeImages} />
|
2023-09-28 23:50:27 +02:00
|
|
|
<Tr t={t.howTo.intro} />
|
2023-09-20 01:47:32 +02:00
|
|
|
<ul>
|
|
|
|
<li>
|
|
|
|
<Tr t={t.howTo.li0} />
|
|
|
|
</li>
|
|
|
|
<li>
|
|
|
|
<Tr t={t.howTo.li1} />
|
|
|
|
</li>
|
|
|
|
<li>
|
|
|
|
<Tr t={t.howTo.li2} />
|
|
|
|
</li>
|
|
|
|
<li>
|
|
|
|
<Tr t={t.howTo.li3} />
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
|
|
</div>
|
|
|
|
{:else if selectedOption === undefined}
|
2023-09-28 23:50:27 +02:00
|
|
|
<PlantNetSpeciesList
|
|
|
|
{options}
|
|
|
|
numberOfImages={$imageUrls.length}
|
|
|
|
on:selected={(species) => speciesSelected(species.detail)}
|
|
|
|
>
|
|
|
|
<XCircleIcon
|
|
|
|
slot="upper-right"
|
|
|
|
class="m-4 h-8 w-8 cursor-pointer"
|
|
|
|
on:click={() => {
|
|
|
|
collapsedMode = true
|
|
|
|
}}
|
|
|
|
/>
|
2023-09-20 01:47:32 +02:00
|
|
|
</PlantNetSpeciesList>
|
|
|
|
{:else if !done}
|
2023-09-28 23:50:27 +02:00
|
|
|
<div class="border-interactive flex flex-col">
|
2023-09-20 01:47:32 +02:00
|
|
|
<div class="m-2">
|
|
|
|
<WikipediaPanel wikiIds={new ImmutableStore([selectedOption])} />
|
|
|
|
</div>
|
2023-09-21 12:13:42 +02:00
|
|
|
<div class="flex flex-col items-stretch">
|
2023-09-28 23:50:27 +02:00
|
|
|
<BackButton
|
|
|
|
on:click={() => {
|
|
|
|
selectedOption = undefined
|
|
|
|
}}
|
|
|
|
>
|
2023-09-20 01:47:32 +02:00
|
|
|
<Tr t={t.back} />
|
|
|
|
</BackButton>
|
2023-09-28 23:50:27 +02:00
|
|
|
<NextButton
|
|
|
|
clss="primary"
|
|
|
|
on:click={() => {
|
|
|
|
done = true
|
|
|
|
onConfirm(selectedOption)
|
|
|
|
}}
|
|
|
|
>
|
2023-09-20 01:47:32 +02:00
|
|
|
<Tr t={t.confirm} />
|
|
|
|
</NextButton>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{:else}
|
|
|
|
<!-- done ! -->
|
|
|
|
<Tr t={t.done} cls="thanks w-full" />
|
2023-09-28 23:50:27 +02:00
|
|
|
<BackButton
|
|
|
|
imageClass="w-6 h-6 shrink-0"
|
|
|
|
clss="p-1 m-0"
|
|
|
|
on:click={() => {
|
|
|
|
done = false
|
|
|
|
selectedOption = undefined
|
|
|
|
}}
|
|
|
|
>
|
2023-09-20 01:47:32 +02:00
|
|
|
<Tr t={t.tryAgain} />
|
|
|
|
</BackButton>
|
|
|
|
{/if}
|
2023-09-28 23:50:27 +02:00
|
|
|
<div class="low-interaction flex self-end rounded-xl p-2">
|
|
|
|
<ToSvelte
|
|
|
|
construct={Svg.plantnet_logo_svg().SetClass("w-8 h-8 p-1 mr-1 bg-white rounded-full")}
|
|
|
|
/>
|
2023-09-20 01:47:32 +02:00
|
|
|
<Tr t={t.poweredByPlantnet} />
|
|
|
|
</div>
|
|
|
|
</div>
|