style: run eslint and prettier
This commit is contained in:
@ -1,2 +1,3 @@
|
|||||||
android/
|
android/
|
||||||
dist/
|
dist/
|
||||||
|
src-tauri/
|
@ -26,7 +26,7 @@ export default tseslint.config(
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
[globalIgnores(["./android", "./dist"])],
|
[globalIgnores(["./android", "./dist", "./src-tauri"])],
|
||||||
{
|
{
|
||||||
languageOptions: {
|
languageOptions: {
|
||||||
globals: {
|
globals: {
|
||||||
|
@ -3,7 +3,10 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
<meta
|
||||||
|
name="viewport"
|
||||||
|
content="width=device-width, initial-scale=1.0, viewport-fit=cover"
|
||||||
|
/>
|
||||||
<link rel="manifest" href="manifest.json" />
|
<link rel="manifest" href="manifest.json" />
|
||||||
<title>TrafficCue</title>
|
<title>TrafficCue</title>
|
||||||
</head>
|
</head>
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
{
|
{
|
||||||
"version": 8,
|
"version": 8,
|
||||||
"sources": {
|
"sources": {},
|
||||||
},
|
|
||||||
"sprite": "https://tiles.openfreemap.org/sprites/ofm_f384/ofm",
|
"sprite": "https://tiles.openfreemap.org/sprites/ofm_f384/ofm",
|
||||||
"glyphs": "https://tiles.openfreemap.org/fonts/{fontstack}/{range}.pbf",
|
"glyphs": "https://tiles.openfreemap.org/fonts/{fontstack}/{range}.pbf",
|
||||||
"layers": []
|
"layers": []
|
||||||
|
@ -10,7 +10,11 @@
|
|||||||
import { location } from "./location.svelte";
|
import { location } from "./location.svelte";
|
||||||
import { saved } from "$lib/saved.svelte";
|
import { saved } from "$lib/saved.svelte";
|
||||||
import RoutingLayers from "$lib/services/navigation/RoutingLayers.svelte";
|
import RoutingLayers from "$lib/services/navigation/RoutingLayers.svelte";
|
||||||
import { getPMTilesURL, hasPMTiles, protocol } from "$lib/services/OfflineTiles";
|
import {
|
||||||
|
getPMTilesURL,
|
||||||
|
hasPMTiles,
|
||||||
|
protocol,
|
||||||
|
} from "$lib/services/OfflineTiles";
|
||||||
import { layers, worldLayers } from "$lib/mapLayers";
|
import { layers, worldLayers } from "$lib/mapLayers";
|
||||||
import { PMTilesProtocol } from "svelte-maplibre-gl/pmtiles";
|
import { PMTilesProtocol } from "svelte-maplibre-gl/pmtiles";
|
||||||
|
|
||||||
@ -44,31 +48,25 @@
|
|||||||
// @ts-expect-error - not typed
|
// @ts-expect-error - not typed
|
||||||
window.map = map.value;
|
window.map = map.value;
|
||||||
|
|
||||||
// const worldUrl = await getPMTiles("world");
|
map.value!.addSource("ne2_shaded", {
|
||||||
// if(worldUrl) {
|
// TODO: rename to world
|
||||||
map.value!.addSource("ne2_shaded", { // TODO: rename to world
|
|
||||||
type: "vector",
|
type: "vector",
|
||||||
url: await getPMTilesURL("world"),
|
url: await getPMTilesURL("world"),
|
||||||
attribution: "Natural Earth",
|
attribution: "Natural Earth",
|
||||||
// maxzoom: 6
|
});
|
||||||
})
|
|
||||||
|
|
||||||
// @ts-expect-error - not typed correctly
|
// @ts-expect-error - not typed correctly
|
||||||
worldLayers.forEach(l => map.value!.addLayer(l));
|
worldLayers.forEach((l) => map.value!.addLayer(l));
|
||||||
// }
|
|
||||||
|
|
||||||
// const url = await getPMTiles("tiles");
|
|
||||||
// console.log(url)
|
|
||||||
// if(url) {
|
|
||||||
map.value!.addSource("openmaptiles", {
|
map.value!.addSource("openmaptiles", {
|
||||||
type: "vector",
|
type: "vector",
|
||||||
url: await hasPMTiles("tiles") ? await getPMTilesURL("tiles") : "pmtiles://https://trafficcue-tiles.picoscratch.de/germany.pmtiles"
|
url: (await hasPMTiles("tiles"))
|
||||||
})
|
? await getPMTilesURL("tiles")
|
||||||
|
: "pmtiles://https://trafficcue-tiles.picoscratch.de/germany.pmtiles",
|
||||||
|
});
|
||||||
|
|
||||||
// @ts-expect-error - not typed correctly
|
// @ts-expect-error - not typed correctly
|
||||||
layers.forEach(l => map.value!.addLayer(l));
|
layers.forEach((l) => map.value!.addLayer(l));
|
||||||
// }
|
|
||||||
}}
|
}}
|
||||||
onclick={(e) => {
|
onclick={(e) => {
|
||||||
if (view.current.type == "main" || view.current.type == "info") {
|
if (view.current.type == "main" || view.current.type == "info") {
|
||||||
|
@ -27,8 +27,6 @@
|
|||||||
import * as Popover from "../ui/popover";
|
import * as Popover from "../ui/popover";
|
||||||
import { routing } from "$lib/services/navigation/routing.svelte";
|
import { routing } from "$lib/services/navigation/routing.svelte";
|
||||||
import InRouteSidebar from "./sidebar/InRouteSidebar.svelte";
|
import InRouteSidebar from "./sidebar/InRouteSidebar.svelte";
|
||||||
import say from "$lib/services/navigation/TTS";
|
|
||||||
import { downloadPMTiles } from "$lib/services/OfflineTiles";
|
|
||||||
import SettingsSidebar from "./sidebar/settings/SettingsSidebar.svelte";
|
import SettingsSidebar from "./sidebar/settings/SettingsSidebar.svelte";
|
||||||
import AboutSidebar from "./sidebar/settings/AboutSidebar.svelte";
|
import AboutSidebar from "./sidebar/settings/AboutSidebar.svelte";
|
||||||
import OfflineMapsSidebar from "./sidebar/settings/OfflineMapsSidebar.svelte";
|
import OfflineMapsSidebar from "./sidebar/settings/OfflineMapsSidebar.svelte";
|
||||||
@ -45,7 +43,7 @@
|
|||||||
settings: SettingsSidebar,
|
settings: SettingsSidebar,
|
||||||
about: AboutSidebar,
|
about: AboutSidebar,
|
||||||
"offline-maps": OfflineMapsSidebar,
|
"offline-maps": OfflineMapsSidebar,
|
||||||
"dev-options": DeveloperSidebar
|
"dev-options": DeveloperSidebar,
|
||||||
};
|
};
|
||||||
|
|
||||||
let isDragging = false;
|
let isDragging = false;
|
||||||
@ -164,9 +162,11 @@
|
|||||||
<UserIcon />
|
<UserIcon />
|
||||||
</button>
|
</button>
|
||||||
</RequiresCapability>
|
</RequiresCapability>
|
||||||
<button onclick={() => {
|
<button
|
||||||
|
onclick={() => {
|
||||||
view.switch("settings");
|
view.switch("settings");
|
||||||
}}>
|
}}
|
||||||
|
>
|
||||||
<SettingsIcon />
|
<SettingsIcon />
|
||||||
</button>
|
</button>
|
||||||
<!-- <button onclick={() => {
|
<!-- <button onclick={() => {
|
||||||
|
@ -6,18 +6,21 @@
|
|||||||
const dev = getDeveloperToggle();
|
const dev = getDeveloperToggle();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<SidebarHeader>
|
<SidebarHeader>About</SidebarHeader>
|
||||||
About
|
|
||||||
</SidebarHeader>
|
|
||||||
|
|
||||||
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
||||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||||
<h1 style="font-size: 2em; font-weight: bold;" onclick={() => {
|
<h1
|
||||||
|
style="font-size: 2em; font-weight: bold;"
|
||||||
|
onclick={() => {
|
||||||
count--;
|
count--;
|
||||||
if(count == 0) {
|
if (count == 0) {
|
||||||
dev.current = "true";
|
dev.current = "true";
|
||||||
}
|
}
|
||||||
}}>TrafficCue</h1>
|
}}
|
||||||
|
>
|
||||||
|
TrafficCue
|
||||||
|
</h1>
|
||||||
<span>Powered by:</span>
|
<span>Powered by:</span>
|
||||||
<ul>
|
<ul>
|
||||||
<li>© OpenStreetMap contributors</li>
|
<li>© OpenStreetMap contributors</li>
|
||||||
|
@ -10,31 +10,42 @@
|
|||||||
const dev = getDeveloperToggle();
|
const dev = getDeveloperToggle();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<SidebarHeader>
|
<SidebarHeader>Developer Settings</SidebarHeader>
|
||||||
Developer Settings
|
|
||||||
</SidebarHeader>
|
|
||||||
|
|
||||||
<div id="sections">
|
<div id="sections">
|
||||||
<section>
|
<section>
|
||||||
<h2>Test</h2>
|
<h2>Test</h2>
|
||||||
<SettingsButton icon={SpeechIcon} text="Test TTS" onclick={async () => {
|
<SettingsButton
|
||||||
await say("Test")
|
icon={SpeechIcon}
|
||||||
}} />
|
text="Test TTS"
|
||||||
<SettingsButton icon={MapIcon} disabled={!window.__TAURI__} text="Download tiles from URL{window.__TAURI__ ? "" : " (Unavailable)"}" onclick={async () => {
|
onclick={async () => {
|
||||||
|
await say("Test");
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<SettingsButton
|
||||||
|
icon={MapIcon}
|
||||||
|
disabled={!window.__TAURI__}
|
||||||
|
text="Download tiles from URL{window.__TAURI__ ? '' : ' (Unavailable)'}"
|
||||||
|
onclick={async () => {
|
||||||
const name = prompt("Name?");
|
const name = prompt("Name?");
|
||||||
if(!name) return;
|
if (!name) return;
|
||||||
const url = prompt("URL?");
|
const url = prompt("URL?");
|
||||||
if(!url) return;
|
if (!url) return;
|
||||||
await downloadPMTiles(url, name);
|
await downloadPMTiles(url, name);
|
||||||
}} />
|
}}
|
||||||
|
/>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<h2>Other</h2>
|
<h2>Other</h2>
|
||||||
<SettingsButton icon={ToggleLeftIcon} text="Disable Developer Options" onclick={async () => {
|
<SettingsButton
|
||||||
|
icon={ToggleLeftIcon}
|
||||||
|
text="Disable Developer Options"
|
||||||
|
onclick={async () => {
|
||||||
dev.current = "false";
|
dev.current = "false";
|
||||||
view.back();
|
view.back();
|
||||||
}} />
|
}}
|
||||||
|
/>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -4,12 +4,10 @@
|
|||||||
import SettingsButton from "./SettingsButton.svelte";
|
import SettingsButton from "./SettingsButton.svelte";
|
||||||
import SidebarHeader from "../SidebarHeader.svelte";
|
import SidebarHeader from "../SidebarHeader.svelte";
|
||||||
|
|
||||||
let progresses: {[key: string]: number} = $state({});
|
let progresses: Record<string, number> = $state({});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<SidebarHeader>
|
<SidebarHeader>Offline Maps</SidebarHeader>
|
||||||
Offline Maps
|
|
||||||
</SidebarHeader>
|
|
||||||
|
|
||||||
{#await getRemoteList()}
|
{#await getRemoteList()}
|
||||||
<p>Loading...</p>
|
<p>Loading...</p>
|
||||||
@ -24,13 +22,23 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#each list as item, _index (item.file)}
|
{#each list as item, _index (item.file)}
|
||||||
<SettingsButton disabled={!window.__TAURI__} icon={DownloadCloudIcon} text={item.name} progress={progresses[item.file] ?? -1} onclick={async () => {
|
<SettingsButton
|
||||||
await downloadPMTiles("https://trafficcue-tiles.picoscratch.de/" + item.file, item.name.includes("World") ? "world": "tiles", (progress, total) => {
|
disabled={!window.__TAURI__}
|
||||||
|
icon={DownloadCloudIcon}
|
||||||
|
text={item.name}
|
||||||
|
progress={progresses[item.file] ?? -1}
|
||||||
|
onclick={async () => {
|
||||||
|
await downloadPMTiles(
|
||||||
|
"https://trafficcue-tiles.picoscratch.de/" + item.file,
|
||||||
|
item.name.includes("World") ? "world" : "tiles",
|
||||||
|
(progress, total) => {
|
||||||
progresses[item.file] = (progress / total) * 100;
|
progresses[item.file] = (progress / total) * 100;
|
||||||
});
|
},
|
||||||
|
);
|
||||||
alert(`Downloaded ${item.name}`);
|
alert(`Downloaded ${item.name}`);
|
||||||
location.reload();
|
location.reload();
|
||||||
}} />
|
}}
|
||||||
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
{/await}
|
{/await}
|
@ -6,16 +6,31 @@
|
|||||||
import Progress from "$lib/components/ui/progress/progress.svelte";
|
import Progress from "$lib/components/ui/progress/progress.svelte";
|
||||||
|
|
||||||
const {
|
const {
|
||||||
icon: Icon, text, view: viewName, onclick, disabled, progress
|
icon: Icon,
|
||||||
|
text,
|
||||||
|
view: viewName,
|
||||||
|
onclick,
|
||||||
|
disabled,
|
||||||
|
progress,
|
||||||
}: {
|
}: {
|
||||||
icon: Component<IconProps>, text: string, view?: string, onclick?: () => void, disabled?: boolean, progress?: number
|
icon: Component<IconProps>;
|
||||||
|
text: string;
|
||||||
|
view?: string;
|
||||||
|
onclick?: () => void;
|
||||||
|
disabled?: boolean;
|
||||||
|
progress?: number;
|
||||||
} = $props();
|
} = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Button variant="secondary" style="width: 100%; height: 40px;" {disabled} onclick={() => {
|
<Button
|
||||||
if(viewName) view.switch(viewName)
|
variant="secondary"
|
||||||
if(onclick) onclick();
|
style="width: 100%; height: 40px;"
|
||||||
}}>
|
{disabled}
|
||||||
|
onclick={() => {
|
||||||
|
if (viewName) view.switch(viewName);
|
||||||
|
if (onclick) onclick();
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Icon />
|
<Icon />
|
||||||
{text}
|
{text}
|
||||||
{#if progress == -1}
|
{#if progress == -1}
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
<script>
|
<script>
|
||||||
import { CodeIcon, InfoIcon, LanguagesIcon, MapIcon, PaintbrushIcon } from "@lucide/svelte";
|
import {
|
||||||
|
CodeIcon,
|
||||||
|
InfoIcon,
|
||||||
|
LanguagesIcon,
|
||||||
|
MapIcon,
|
||||||
|
PaintbrushIcon,
|
||||||
|
} from "@lucide/svelte";
|
||||||
import SidebarHeader from "../SidebarHeader.svelte";
|
import SidebarHeader from "../SidebarHeader.svelte";
|
||||||
import SettingsButton from "./SettingsButton.svelte";
|
import SettingsButton from "./SettingsButton.svelte";
|
||||||
import { getDeveloperToggle } from "./developer.svelte";
|
import { getDeveloperToggle } from "./developer.svelte";
|
||||||
@ -7,9 +13,7 @@
|
|||||||
const dev = getDeveloperToggle();
|
const dev = getDeveloperToggle();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<SidebarHeader>
|
<SidebarHeader>Settings</SidebarHeader>
|
||||||
Settings
|
|
||||||
</SidebarHeader>
|
|
||||||
|
|
||||||
<div id="sections">
|
<div id="sections">
|
||||||
<section>
|
<section>
|
||||||
@ -26,7 +30,11 @@
|
|||||||
<section>
|
<section>
|
||||||
<h2>About</h2>
|
<h2>About</h2>
|
||||||
{#if dev.current == "true"}
|
{#if dev.current == "true"}
|
||||||
<SettingsButton icon={CodeIcon} text="Developer Settings" view="dev-options" />
|
<SettingsButton
|
||||||
|
icon={CodeIcon}
|
||||||
|
text="Developer Settings"
|
||||||
|
view="dev-options"
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
<SettingsButton icon={InfoIcon} text="About" view="about" />
|
<SettingsButton icon={InfoIcon} text="About" view="about" />
|
||||||
</section>
|
</section>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
export function getDeveloperToggle() {
|
export function getDeveloperToggle() {
|
||||||
const value = localStorage.getItem("developer")
|
const value = localStorage.getItem("developer");
|
||||||
const state = $state({
|
const state = $state({
|
||||||
current: value == null ? "false" : value
|
current: value == null ? "false" : value,
|
||||||
});
|
});
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
|
@ -14,7 +14,10 @@
|
|||||||
<ProgressPrimitive.Root
|
<ProgressPrimitive.Root
|
||||||
bind:ref
|
bind:ref
|
||||||
data-slot="progress"
|
data-slot="progress"
|
||||||
class={cn("bg-primary/20 relative h-2 w-full overflow-hidden rounded-full", className)}
|
class={cn(
|
||||||
|
"bg-primary/20 relative h-2 w-full overflow-hidden rounded-full",
|
||||||
|
className,
|
||||||
|
)}
|
||||||
{value}
|
{value}
|
||||||
{max}
|
{max}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
|
1336
src/lib/mapLayers.ts
1336
src/lib/mapLayers.ts
File diff suppressed because it is too large
Load Diff
@ -1,22 +1,33 @@
|
|||||||
import { appDataDir, join } from "@tauri-apps/api/path";
|
import { appDataDir, join } from "@tauri-apps/api/path";
|
||||||
import { BaseDirectory, exists, mkdir, open, remove, SeekMode } from "@tauri-apps/plugin-fs";
|
import {
|
||||||
|
BaseDirectory,
|
||||||
|
exists,
|
||||||
|
mkdir,
|
||||||
|
open,
|
||||||
|
remove,
|
||||||
|
SeekMode,
|
||||||
|
} from "@tauri-apps/plugin-fs";
|
||||||
import { download } from "@tauri-apps/plugin-upload";
|
import { download } from "@tauri-apps/plugin-upload";
|
||||||
import { PMTiles, TileType, type Source } from "pmtiles";
|
import { PMTiles, TileType, type Source } from "pmtiles";
|
||||||
|
|
||||||
export async function downloadPMTiles(url: string, name: string, onprogress?: (progress: number, total: number) => any): Promise<void> {
|
export async function downloadPMTiles(
|
||||||
// if(!window.__TAURI__) {
|
url: string,
|
||||||
// throw new Error("Tauri environment is not available.");
|
name: string,
|
||||||
// }
|
onprogress?: (progress: number, total: number) => void,
|
||||||
|
): Promise<void> {
|
||||||
|
// if(!window.__TAURI__) {
|
||||||
|
// throw new Error("Tauri environment is not available.");
|
||||||
|
// }
|
||||||
|
|
||||||
const filename = name + ".pmtiles";
|
const filename = name + ".pmtiles";
|
||||||
const baseDir = BaseDirectory.AppData;
|
const baseDir = BaseDirectory.AppData;
|
||||||
const appDataDirPath = await appDataDir();
|
const appDataDirPath = await appDataDir();
|
||||||
|
|
||||||
if(!await exists(appDataDirPath)) {
|
if (!(await exists(appDataDirPath))) {
|
||||||
await mkdir(appDataDirPath, { recursive: true });
|
await mkdir(appDataDirPath, { recursive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
if(await exists(filename, { baseDir })) {
|
if (await exists(filename, { baseDir })) {
|
||||||
console.log(`File ${filename} already exists, deleting it.`);
|
console.log(`File ${filename} already exists, deleting it.`);
|
||||||
await remove(filename, { baseDir });
|
await remove(filename, { baseDir });
|
||||||
}
|
}
|
||||||
@ -33,19 +44,25 @@ export async function downloadPMTiles(url: string, name: string, onprogress?: (p
|
|||||||
let totalProgress = 0;
|
let totalProgress = 0;
|
||||||
await download(url, path, ({ progress, total }) => {
|
await download(url, path, ({ progress, total }) => {
|
||||||
totalProgress += progress;
|
totalProgress += progress;
|
||||||
console.log(`Download progress: ${Math.round((totalProgress / total) * 100)}% (${totalProgress}\tof ${total} bytes)`);
|
console.log(
|
||||||
if(onprogress) onprogress(totalProgress, total);
|
`Download progress: ${Math.round((totalProgress / total) * 100)}% (${totalProgress}\tof ${total} bytes)`,
|
||||||
|
);
|
||||||
|
if (onprogress) onprogress(totalProgress, total);
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(`Download completed: ${path}`);
|
console.log(`Download completed: ${path}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getRemoteList(): Promise<{ name: string, file: string }[]> {
|
export async function getRemoteList(): Promise<
|
||||||
return await fetch("https://trafficcue-tiles.picoscratch.de/index.json").then(res => res.json());
|
{ name: string; file: string }[]
|
||||||
|
> {
|
||||||
|
return await fetch("https://trafficcue-tiles.picoscratch.de/index.json").then(
|
||||||
|
(res) => res.json(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function hasPMTiles(name: string): Promise<boolean> {
|
export async function hasPMTiles(name: string): Promise<boolean> {
|
||||||
if(!window.__TAURI__) {
|
if (!window.__TAURI__) {
|
||||||
return false; // Tauri environment is not available
|
return false; // Tauri environment is not available
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +70,7 @@ export async function hasPMTiles(name: string): Promise<boolean> {
|
|||||||
const baseDir = BaseDirectory.AppData;
|
const baseDir = BaseDirectory.AppData;
|
||||||
const appDataDirPath = await appDataDir();
|
const appDataDirPath = await appDataDir();
|
||||||
|
|
||||||
if(!await exists(appDataDirPath)) {
|
if (!(await exists(appDataDirPath))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,21 +79,21 @@ export async function hasPMTiles(name: string): Promise<boolean> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getPMTilesURL(name: string) {
|
export async function getPMTilesURL(name: string) {
|
||||||
if(!window.__TAURI__) {
|
if (!window.__TAURI__) {
|
||||||
return `pmtiles://https://trafficcue-tiles.picoscratch.de/${name}.pmtiles`;
|
return `pmtiles://https://trafficcue-tiles.picoscratch.de/${name}.pmtiles`;
|
||||||
}
|
}
|
||||||
const filename = name + ".pmtiles";
|
const filename = name + ".pmtiles";
|
||||||
const baseDir = BaseDirectory.AppData;
|
const baseDir = BaseDirectory.AppData;
|
||||||
const appDataDirPath = await appDataDir();
|
const appDataDirPath = await appDataDir();
|
||||||
|
|
||||||
if(!await exists(appDataDirPath)) {
|
if (!(await exists(appDataDirPath))) {
|
||||||
return `pmtiles://https://trafficcue-tiles.picoscratch.de/${name}.pmtiles`;
|
return `pmtiles://https://trafficcue-tiles.picoscratch.de/${name}.pmtiles`;
|
||||||
// throw new Error("App data directory does not exist.");
|
// throw new Error("App data directory does not exist.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const filePath = await join(appDataDirPath, filename);
|
const filePath = await join(appDataDirPath, filename);
|
||||||
|
|
||||||
if(!await exists(filePath, { baseDir })) {
|
if (!(await exists(filePath, { baseDir }))) {
|
||||||
return `pmtiles://https://trafficcue-tiles.picoscratch.de/${name}.pmtiles`;
|
return `pmtiles://https://trafficcue-tiles.picoscratch.de/${name}.pmtiles`;
|
||||||
// throw new Error(`PMTiles file not found: ${filePath}`);
|
// throw new Error(`PMTiles file not found: ${filePath}`);
|
||||||
}
|
}
|
||||||
@ -84,8 +101,15 @@ export async function getPMTilesURL(name: string) {
|
|||||||
return `tiles://${name}`;
|
return `tiles://${name}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function readBytes(name: string, offset: number, length: number): Promise<Uint8Array> {
|
async function readBytes(
|
||||||
const file = await open(name + ".pmtiles", { read: true, baseDir: BaseDirectory.AppData });
|
name: string,
|
||||||
|
offset: number,
|
||||||
|
length: number,
|
||||||
|
): Promise<Uint8Array> {
|
||||||
|
const file = await open(name + ".pmtiles", {
|
||||||
|
read: true,
|
||||||
|
baseDir: BaseDirectory.AppData,
|
||||||
|
});
|
||||||
const buffer = new Uint8Array(length);
|
const buffer = new Uint8Array(length);
|
||||||
await file.seek(offset, SeekMode.Start);
|
await file.seek(offset, SeekMode.Start);
|
||||||
await file.read(buffer);
|
await file.read(buffer);
|
||||||
@ -100,14 +124,20 @@ export class FSSource implements Source {
|
|||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBytes(offset: number, length: number, _signal?: AbortSignal, _etag?: string) { // TODO: abort signal
|
async getBytes(
|
||||||
|
offset: number,
|
||||||
|
length: number,
|
||||||
|
_signal?: AbortSignal,
|
||||||
|
_etag?: string,
|
||||||
|
) {
|
||||||
|
// TODO: abort signal
|
||||||
const data = await readBytes(this.name, offset, length);
|
const data = await readBytes(this.name, offset, length);
|
||||||
return {
|
return {
|
||||||
data: data.buffer as ArrayBuffer,
|
data: data.buffer as ArrayBuffer,
|
||||||
etag: undefined,
|
etag: undefined,
|
||||||
cacheControl: undefined,
|
cacheControl: undefined,
|
||||||
expires: undefined
|
expires: undefined,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
getKey = () => this.name;
|
getKey = () => this.name;
|
||||||
@ -121,12 +151,13 @@ interface RequestParameters {
|
|||||||
type?: "string" | "json" | "arrayBuffer" | "image";
|
type?: "string" | "json" | "arrayBuffer" | "image";
|
||||||
credentials?: "same-origin" | "include";
|
credentials?: "same-origin" | "include";
|
||||||
collectResourceTiming?: boolean;
|
collectResourceTiming?: boolean;
|
||||||
};
|
}
|
||||||
|
|
||||||
export class Protocol {
|
export class Protocol {
|
||||||
/** @hidden */
|
/** @hidden */
|
||||||
tiles: Map<string, PMTiles>;
|
tiles: Map<string, PMTiles>;
|
||||||
metadata: boolean; errorOnMissingTile: boolean;
|
metadata: boolean;
|
||||||
|
errorOnMissingTile: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the MapLibre PMTiles protocol.
|
* Initialize the MapLibre PMTiles protocol.
|
||||||
@ -163,7 +194,7 @@ export class Protocol {
|
|||||||
/** @hidden */
|
/** @hidden */
|
||||||
tilev4 = async (
|
tilev4 = async (
|
||||||
params: RequestParameters,
|
params: RequestParameters,
|
||||||
abortController: AbortController
|
abortController: AbortController,
|
||||||
) => {
|
) => {
|
||||||
if (params.type === "json") {
|
if (params.type === "json") {
|
||||||
const pmtilesUrl = params.url.substr(8);
|
const pmtilesUrl = params.url.substr(8);
|
||||||
@ -183,7 +214,7 @@ export class Protocol {
|
|||||||
|
|
||||||
if (h.minLon >= h.maxLon || h.minLat >= h.maxLat) {
|
if (h.minLon >= h.maxLon || h.minLat >= h.maxLat) {
|
||||||
console.error(
|
console.error(
|
||||||
`Bounds of PMTiles archive ${h.minLon},${h.minLat},${h.maxLon},${h.maxLat} are not valid.`
|
`Bounds of PMTiles archive ${h.minLon},${h.minLat},${h.maxLon},${h.maxLat} are not valid.`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +60,12 @@ out center tags;`,
|
|||||||
}).then((res) => res.json() as Promise<OverpassResult>);
|
}).then((res) => res.json() as Promise<OverpassResult>);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchNearbyPOI(lat: number, lon: number, tags: string[], radius: number) {
|
export async function fetchNearbyPOI(
|
||||||
|
lat: number,
|
||||||
|
lon: number,
|
||||||
|
tags: string[],
|
||||||
|
radius: number,
|
||||||
|
) {
|
||||||
return await fetch(OVERPASS_SERVER, {
|
return await fetch(OVERPASS_SERVER, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: `[out:json];
|
body: `[out:json];
|
||||||
|
@ -23,7 +23,7 @@ export default async function say(text: string) {
|
|||||||
duck();
|
duck();
|
||||||
if (tts !== "web") {
|
if (tts !== "web") {
|
||||||
try {
|
try {
|
||||||
await invoke("plugin:tts|speak", { text })
|
await invoke("plugin:tts|speak", { text });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Error speaking text", e);
|
console.error("Error speaking text", e);
|
||||||
alert(e);
|
alert(e);
|
||||||
|
@ -129,7 +129,7 @@ function drawCurrentTrip() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function startRoute(trip: Trip) {
|
export async function startRoute(trip: Trip) {
|
||||||
if(window.__TAURI__) {
|
if (window.__TAURI__) {
|
||||||
await keepScreenOn(true);
|
await keepScreenOn(true);
|
||||||
}
|
}
|
||||||
routing.currentTrip = trip;
|
routing.currentTrip = trip;
|
||||||
@ -270,7 +270,7 @@ export function stopNavigation() {
|
|||||||
routing.currentTrip = null;
|
routing.currentTrip = null;
|
||||||
map.updateMapPadding(); // TODO: REMOVE
|
map.updateMapPadding(); // TODO: REMOVE
|
||||||
removeAllRoutes();
|
removeAllRoutes();
|
||||||
if(window.__TAURI__) {
|
if (window.__TAURI__) {
|
||||||
keepScreenOn(false);
|
keepScreenOn(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,22 +12,23 @@ export default defineConfig({
|
|||||||
port: 5173,
|
port: 5173,
|
||||||
strictPort: true,
|
strictPort: true,
|
||||||
host: host || false,
|
host: host || false,
|
||||||
hmr: host ? {
|
hmr: host
|
||||||
|
? {
|
||||||
protocol: "ws",
|
protocol: "ws",
|
||||||
host,
|
host,
|
||||||
port: 1421
|
port: 1421,
|
||||||
} : undefined,
|
|
||||||
watch: {
|
|
||||||
ignored: ["**/src-tauri/**"]
|
|
||||||
}
|
}
|
||||||
|
: undefined,
|
||||||
|
watch: {
|
||||||
|
ignored: ["**/src-tauri/**"],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
envPrefix: ["VITE_", "TAURI_ENV_*"],
|
envPrefix: ["VITE_", "TAURI_ENV_*"],
|
||||||
build: {
|
build: {
|
||||||
target: process.env.TAURI_ENV_PLATFORM == "windows"
|
target:
|
||||||
? "chrome105"
|
process.env.TAURI_ENV_PLATFORM == "windows" ? "chrome105" : "safari13",
|
||||||
: "safari13",
|
|
||||||
minify: !process.env.TAURI_ENV_DEBUG ? "esbuild" : false,
|
minify: !process.env.TAURI_ENV_DEBUG ? "esbuild" : false,
|
||||||
sourcemap: !!process.env.TAURI_ENV_DEBUG
|
sourcemap: !!process.env.TAURI_ENV_DEBUG,
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
|
Reference in New Issue
Block a user