extracted event listeners out of debug components into dedicated files
This commit is contained in:
@@ -1,40 +1,20 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { commands, events, type ConnectionStatus } from "$lib/bindings";
|
||||
|
||||
let statuses: ConnectionStatus[] = [];
|
||||
let error = "";
|
||||
|
||||
onMount(() => {
|
||||
const unlisten = events.networkStatusChanged.listen((event) => {
|
||||
statuses = event.payload.statuses;
|
||||
});
|
||||
|
||||
commands
|
||||
.listStatuses()
|
||||
.then((current) => {
|
||||
statuses = current;
|
||||
})
|
||||
.catch((err) => {
|
||||
error = String(err);
|
||||
});
|
||||
|
||||
return () => {
|
||||
unlisten.then((stop) => stop());
|
||||
};
|
||||
});
|
||||
import {
|
||||
connectionStatuses,
|
||||
connectionStatusesListenerError,
|
||||
} from "$lib/listeners/connection-status";
|
||||
</script>
|
||||
|
||||
<section>
|
||||
<h1>Connections</h1>
|
||||
|
||||
{#if error}
|
||||
<p aria-live="polite">{error}</p>
|
||||
{:else if statuses.length === 0}
|
||||
{#if $connectionStatusesListenerError}
|
||||
<p aria-live="polite">{$connectionStatusesListenerError}</p>
|
||||
{:else if $connectionStatuses.length === 0}
|
||||
<p>No remote connections configured.</p>
|
||||
{:else}
|
||||
<ul aria-live="polite">
|
||||
{#each statuses as status (status.remoteId)}
|
||||
{#each $connectionStatuses as status (status.remoteId)}
|
||||
<li>
|
||||
<strong>{status.name ?? status.address}</strong>: {status.state}
|
||||
{#if status.name}
|
||||
|
||||
@@ -1,24 +1,9 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { commands, events, type User } from "$lib/bindings";
|
||||
import { commands } from "$lib/bindings";
|
||||
import { friends, friendsListenerError } from "$lib/listeners/friends";
|
||||
|
||||
let friends: User[] = [];
|
||||
let error = "";
|
||||
|
||||
onMount(() => {
|
||||
const unlisten = events.friendsChanged.listen((event) => {
|
||||
friends = event.payload.friends;
|
||||
});
|
||||
|
||||
commands.listFriends().catch((err) => {
|
||||
error = String(err);
|
||||
});
|
||||
|
||||
return () => {
|
||||
unlisten.then((stop) => stop());
|
||||
};
|
||||
});
|
||||
|
||||
async function createFriend(event: SubmitEvent) {
|
||||
const form = event.currentTarget as HTMLFormElement;
|
||||
const data = new FormData(form);
|
||||
@@ -68,15 +53,15 @@
|
||||
<button type="submit">Create friend</button>
|
||||
</form>
|
||||
|
||||
{#if error}
|
||||
<p>{error}</p>
|
||||
{#if error || $friendsListenerError}
|
||||
<p>{error || $friendsListenerError}</p>
|
||||
{/if}
|
||||
|
||||
{#if friends.length === 0}
|
||||
{#if $friends.length === 0}
|
||||
<p>No friends saved.</p>
|
||||
{:else}
|
||||
<ul>
|
||||
{#each friends as friend (friend.id)}
|
||||
{#each $friends as friend (friend.id)}
|
||||
<li>
|
||||
<span>{friend.displayName} ({friend.id})</span>
|
||||
<button type="button" onclick={() => deleteFriend(friend.id)}>Delete</button>
|
||||
|
||||
@@ -1,28 +1,15 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import {
|
||||
commands,
|
||||
events,
|
||||
type AppMeta,
|
||||
type CursorPositions,
|
||||
} from "$lib/bindings";
|
||||
|
||||
let localId = "";
|
||||
let cursorPositions: Partial<Record<string, CursorPositions>> = {};
|
||||
let foregroundApps = new Map<string, AppMeta>();
|
||||
let pendingLocalForegroundApp: AppMeta | null = null;
|
||||
let error = "";
|
||||
|
||||
function updateForegroundApp(userId: string, meta: AppMeta) {
|
||||
foregroundApps = new Map(foregroundApps).set(userId, meta);
|
||||
}
|
||||
liveMetadata,
|
||||
liveMetadataListenerError,
|
||||
} from "$lib/listeners/live-metadata";
|
||||
|
||||
function liveUserIds() {
|
||||
return [
|
||||
...new Set([
|
||||
localId,
|
||||
...Object.keys(cursorPositions),
|
||||
...foregroundApps.keys(),
|
||||
$liveMetadata.localId,
|
||||
...Object.keys($liveMetadata.cursorPositions),
|
||||
...$liveMetadata.foregroundApps.keys(),
|
||||
]),
|
||||
].filter(Boolean);
|
||||
}
|
||||
@@ -30,69 +17,21 @@
|
||||
function compactId(id: string) {
|
||||
return id.length > 16 ? `${id.slice(0, 8)}…${id.slice(-6)}` : id;
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
let disposed = false;
|
||||
let stopListeners: (() => void)[] = [];
|
||||
|
||||
async function initialize() {
|
||||
const listeners = await Promise.all([
|
||||
events.cursorPositionChanged.listen((event) => {
|
||||
if (!disposed) cursorPositions = event.payload.positions;
|
||||
}),
|
||||
events.foregroundAppChanged.listen((event) => {
|
||||
if (disposed) return;
|
||||
if (localId) {
|
||||
updateForegroundApp(localId, event.payload.meta);
|
||||
} else {
|
||||
pendingLocalForegroundApp = event.payload.meta;
|
||||
}
|
||||
}),
|
||||
events.friendForegroundAppChanged.listen((event) => {
|
||||
if (!disposed) {
|
||||
updateForegroundApp(event.payload.friendId, event.payload.meta);
|
||||
}
|
||||
}),
|
||||
]);
|
||||
|
||||
if (disposed) {
|
||||
listeners.forEach((stop) => stop());
|
||||
return;
|
||||
}
|
||||
stopListeners = listeners;
|
||||
|
||||
localId = await commands.getPublicKey();
|
||||
if (disposed) return;
|
||||
if (pendingLocalForegroundApp) {
|
||||
updateForegroundApp(localId, pendingLocalForegroundApp);
|
||||
pendingLocalForegroundApp = null;
|
||||
}
|
||||
}
|
||||
|
||||
initialize().catch((err) => {
|
||||
if (!disposed) error = String(err);
|
||||
});
|
||||
|
||||
return () => {
|
||||
disposed = true;
|
||||
stopListeners.forEach((stop) => stop());
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<section>
|
||||
<h1>Live metadata</h1>
|
||||
|
||||
{#if error}
|
||||
<p>{error}</p>
|
||||
{#if $liveMetadataListenerError}
|
||||
<p>{$liveMetadataListenerError}</p>
|
||||
{:else if liveUserIds().length === 0}
|
||||
<p>Waiting for live metadata...</p>
|
||||
{:else}
|
||||
{#each liveUserIds() as userId (userId)}
|
||||
{@const cursor = cursorPositions[userId]}
|
||||
{@const foregroundApp = foregroundApps.get(userId)}
|
||||
{@const cursor = $liveMetadata.cursorPositions[userId]}
|
||||
{@const foregroundApp = $liveMetadata.foregroundApps.get(userId)}
|
||||
<article>
|
||||
<h2>{userId === localId ? "Local user" : "Remote user"}</h2>
|
||||
<h2>{userId === $liveMetadata.localId ? "Local user" : "Remote user"}</h2>
|
||||
<p title={userId}>ID: {compactId(userId)}</p>
|
||||
|
||||
<h3>Cursor</h3>
|
||||
|
||||
@@ -1,39 +1,11 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { commands, events, type User } from "$lib/bindings";
|
||||
import { commands } from "$lib/bindings";
|
||||
import { profile, profileListenerError } from "$lib/listeners/profile";
|
||||
|
||||
let profile: User | null = null;
|
||||
let displayName = "";
|
||||
let error = "";
|
||||
|
||||
onMount(() => {
|
||||
let stop: (() => void) | undefined;
|
||||
let disposed = false;
|
||||
|
||||
async function initialize() {
|
||||
const unlisten = await events.profileChanged.listen((event) => {
|
||||
profile = event.payload.profile;
|
||||
displayName = event.payload.profile.displayName;
|
||||
});
|
||||
|
||||
if (disposed) {
|
||||
unlisten();
|
||||
return;
|
||||
}
|
||||
|
||||
stop = unlisten;
|
||||
await commands.getProfile();
|
||||
}
|
||||
|
||||
initialize().catch((err) => {
|
||||
error = String(err);
|
||||
});
|
||||
|
||||
return () => {
|
||||
disposed = true;
|
||||
stop?.();
|
||||
};
|
||||
});
|
||||
$: displayName = $profile?.displayName ?? "";
|
||||
|
||||
async function updateProfile(event: SubmitEvent) {
|
||||
event.preventDefault();
|
||||
@@ -50,8 +22,8 @@
|
||||
<section>
|
||||
<h1>Profile</h1>
|
||||
|
||||
{#if profile}
|
||||
<p>Public key: {profile.id}</p>
|
||||
{#if $profile}
|
||||
<p>Public key: {$profile.id}</p>
|
||||
{:else}
|
||||
<p>Loading profile...</p>
|
||||
{/if}
|
||||
@@ -64,7 +36,7 @@
|
||||
<button type="submit">Save profile</button>
|
||||
</form>
|
||||
|
||||
{#if error}
|
||||
<p>{error}</p>
|
||||
{#if error || $profileListenerError}
|
||||
<p>{error || $profileListenerError}</p>
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
@@ -1,25 +1,10 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { commands, events, type Remote, type RemoteInput } from "$lib/bindings";
|
||||
import { commands, type RemoteInput } from "$lib/bindings";
|
||||
import { remotes, remotesListenerError } from "$lib/listeners/remotes";
|
||||
|
||||
let remotes: Remote[] = [];
|
||||
let editingId: string | null = null;
|
||||
let error = "";
|
||||
|
||||
onMount(() => {
|
||||
const unlisten = events.remotesChanged.listen((event) => {
|
||||
remotes = event.payload.remotes;
|
||||
});
|
||||
|
||||
commands.listRemotes().catch((err) => {
|
||||
error = String(err);
|
||||
});
|
||||
|
||||
return () => {
|
||||
unlisten.then((stop) => stop());
|
||||
};
|
||||
});
|
||||
|
||||
function remoteInput(form: HTMLFormElement): RemoteInput {
|
||||
const data = new FormData(form);
|
||||
const name = String(data.get("name") ?? "").trim();
|
||||
@@ -98,15 +83,15 @@
|
||||
<button type="submit">Create remote</button>
|
||||
</form>
|
||||
|
||||
{#if error}
|
||||
<p aria-live="polite">{error}</p>
|
||||
{#if error || $remotesListenerError}
|
||||
<p aria-live="polite">{error || $remotesListenerError}</p>
|
||||
{/if}
|
||||
|
||||
{#if remotes.length === 0}
|
||||
{#if $remotes.length === 0}
|
||||
<p>No remotes saved.</p>
|
||||
{:else}
|
||||
<ul>
|
||||
{#each remotes as remote (remote.id)}
|
||||
{#each $remotes as remote (remote.id)}
|
||||
<li>
|
||||
{#if editingId === remote.id}
|
||||
<form onsubmit={(event) => updateRemote(event, remote.id)}>
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import { writable } from "svelte/store";
|
||||
import { commands, events, type ConnectionStatus } from "$lib/bindings";
|
||||
|
||||
export const connectionStatuses = writable<ConnectionStatus[]>([]);
|
||||
export const connectionStatusesListenerError = writable("");
|
||||
|
||||
export async function initConnectionStatusesListener() {
|
||||
const unlisten = await events.networkStatusChanged.listen((event) => {
|
||||
connectionStatuses.set(event.payload.statuses);
|
||||
});
|
||||
|
||||
try {
|
||||
connectionStatuses.set(await commands.listStatuses());
|
||||
} catch (error) {
|
||||
connectionStatusesListenerError.set(String(error));
|
||||
}
|
||||
|
||||
return unlisten;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { writable } from "svelte/store";
|
||||
import { commands, events, type User } from "$lib/bindings";
|
||||
|
||||
export const friends = writable<User[]>([]);
|
||||
export const friendsListenerError = writable("");
|
||||
|
||||
export async function initFriendsListener() {
|
||||
const unlisten = await events.friendsChanged.listen((event) => {
|
||||
friends.set(event.payload.friends);
|
||||
});
|
||||
|
||||
try {
|
||||
friends.set(await commands.listFriends());
|
||||
} catch (error) {
|
||||
friendsListenerError.set(String(error));
|
||||
}
|
||||
|
||||
return unlisten;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import { initConnectionStatusesListener } from "./connection-status";
|
||||
import { initFriendsListener } from "./friends";
|
||||
import { initLiveMetadataListeners } from "./live-metadata";
|
||||
import { initProfileListener } from "./profile";
|
||||
import { initRemotesListener } from "./remotes";
|
||||
|
||||
type Unlisten = () => void;
|
||||
|
||||
export function initAppListeners(): Unlisten {
|
||||
let disposed = false;
|
||||
let unlisteners: Unlisten[] = [];
|
||||
|
||||
Promise.allSettled([
|
||||
initFriendsListener(),
|
||||
initRemotesListener(),
|
||||
initProfileListener(),
|
||||
initConnectionStatusesListener(),
|
||||
initLiveMetadataListeners(),
|
||||
])
|
||||
.then((results) => {
|
||||
const listeners = results.flatMap((result) =>
|
||||
result.status === "fulfilled" ? [result.value] : [],
|
||||
);
|
||||
|
||||
results.forEach((result) => {
|
||||
if (result.status === "rejected") {
|
||||
console.error("failed to initialize app listener", result.reason);
|
||||
}
|
||||
});
|
||||
|
||||
if (disposed) {
|
||||
listeners.forEach((unlisten) => unlisten());
|
||||
} else {
|
||||
unlisteners = listeners;
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
disposed = true;
|
||||
unlisteners.forEach((unlisten) => unlisten());
|
||||
unlisteners = [];
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
import { writable } from "svelte/store";
|
||||
import {
|
||||
commands,
|
||||
events,
|
||||
type AppMeta,
|
||||
type CursorPositions,
|
||||
} from "$lib/bindings";
|
||||
|
||||
export type LiveMetadata = {
|
||||
localId: string;
|
||||
cursorPositions: Partial<Record<string, CursorPositions>>;
|
||||
foregroundApps: Map<string, AppMeta>;
|
||||
};
|
||||
|
||||
export const liveMetadata = writable<LiveMetadata>({
|
||||
localId: "",
|
||||
cursorPositions: {},
|
||||
foregroundApps: new Map(),
|
||||
});
|
||||
export const liveMetadataListenerError = writable("");
|
||||
|
||||
export async function initLiveMetadataListeners() {
|
||||
let localId = "";
|
||||
let pendingLocalForegroundApp: AppMeta | null = null;
|
||||
|
||||
const updateForegroundApp = (userId: string, meta: AppMeta) => {
|
||||
liveMetadata.update((current) => ({
|
||||
...current,
|
||||
foregroundApps: new Map(current.foregroundApps).set(userId, meta),
|
||||
}));
|
||||
};
|
||||
|
||||
const unlisteners = await Promise.all([
|
||||
events.cursorPositionChanged.listen((event) => {
|
||||
liveMetadata.update((current) => ({
|
||||
...current,
|
||||
cursorPositions: event.payload.positions,
|
||||
}));
|
||||
}),
|
||||
events.foregroundAppChanged.listen((event) => {
|
||||
if (localId) {
|
||||
updateForegroundApp(localId, event.payload.meta);
|
||||
} else {
|
||||
pendingLocalForegroundApp = event.payload.meta;
|
||||
}
|
||||
}),
|
||||
events.friendForegroundAppChanged.listen((event) => {
|
||||
updateForegroundApp(event.payload.friendId, event.payload.meta);
|
||||
}),
|
||||
]);
|
||||
|
||||
try {
|
||||
localId = await commands.getPublicKey();
|
||||
liveMetadata.update((current) => ({ ...current, localId }));
|
||||
|
||||
if (pendingLocalForegroundApp) {
|
||||
updateForegroundApp(localId, pendingLocalForegroundApp);
|
||||
pendingLocalForegroundApp = null;
|
||||
}
|
||||
} catch (error) {
|
||||
liveMetadataListenerError.set(String(error));
|
||||
}
|
||||
|
||||
return () => unlisteners.forEach((unlisten) => unlisten());
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { writable } from "svelte/store";
|
||||
import { commands, events, type User } from "$lib/bindings";
|
||||
|
||||
export const profile = writable<User | null>(null);
|
||||
export const profileListenerError = writable("");
|
||||
|
||||
export async function initProfileListener() {
|
||||
const unlisten = await events.profileChanged.listen((event) => {
|
||||
profile.set(event.payload.profile);
|
||||
});
|
||||
|
||||
try {
|
||||
profile.set(await commands.getProfile());
|
||||
} catch (error) {
|
||||
profileListenerError.set(String(error));
|
||||
}
|
||||
|
||||
return unlisten;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { writable } from "svelte/store";
|
||||
import { commands, events, type Remote } from "$lib/bindings";
|
||||
|
||||
export const remotes = writable<Remote[]>([]);
|
||||
export const remotesListenerError = writable("");
|
||||
|
||||
export async function initRemotesListener() {
|
||||
const unlisten = await events.remotesChanged.listen((event) => {
|
||||
remotes.set(event.payload.remotes);
|
||||
});
|
||||
|
||||
try {
|
||||
remotes.set(await commands.listRemotes());
|
||||
} catch (error) {
|
||||
remotesListenerError.set(String(error));
|
||||
}
|
||||
|
||||
return unlisten;
|
||||
}
|
||||
@@ -1,8 +1,13 @@
|
||||
<script>
|
||||
import { browser } from "$app/environment";
|
||||
import { onMount } from "svelte";
|
||||
import { initAppListeners } from "$lib/listeners";
|
||||
import "../app.css";
|
||||
|
||||
let { children } = $props();
|
||||
|
||||
onMount(initAppListeners);
|
||||
|
||||
if (browser) {
|
||||
document.addEventListener("contextmenu", (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
Reference in New Issue
Block a user