extracted event listeners out of debug components into dedicated files
This commit is contained in:
@@ -1,40 +1,20 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount } from "svelte";
|
import {
|
||||||
import { commands, events, type ConnectionStatus } from "$lib/bindings";
|
connectionStatuses,
|
||||||
|
connectionStatusesListenerError,
|
||||||
let statuses: ConnectionStatus[] = [];
|
} from "$lib/listeners/connection-status";
|
||||||
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());
|
|
||||||
};
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<h1>Connections</h1>
|
<h1>Connections</h1>
|
||||||
|
|
||||||
{#if error}
|
{#if $connectionStatusesListenerError}
|
||||||
<p aria-live="polite">{error}</p>
|
<p aria-live="polite">{$connectionStatusesListenerError}</p>
|
||||||
{:else if statuses.length === 0}
|
{:else if $connectionStatuses.length === 0}
|
||||||
<p>No remote connections configured.</p>
|
<p>No remote connections configured.</p>
|
||||||
{:else}
|
{:else}
|
||||||
<ul aria-live="polite">
|
<ul aria-live="polite">
|
||||||
{#each statuses as status (status.remoteId)}
|
{#each $connectionStatuses as status (status.remoteId)}
|
||||||
<li>
|
<li>
|
||||||
<strong>{status.name ?? status.address}</strong>: {status.state}
|
<strong>{status.name ?? status.address}</strong>: {status.state}
|
||||||
{#if status.name}
|
{#if status.name}
|
||||||
|
|||||||
@@ -1,24 +1,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount } from "svelte";
|
import { commands } from "$lib/bindings";
|
||||||
import { commands, events, type User } from "$lib/bindings";
|
import { friends, friendsListenerError } from "$lib/listeners/friends";
|
||||||
|
|
||||||
let friends: User[] = [];
|
|
||||||
let error = "";
|
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) {
|
async function createFriend(event: SubmitEvent) {
|
||||||
const form = event.currentTarget as HTMLFormElement;
|
const form = event.currentTarget as HTMLFormElement;
|
||||||
const data = new FormData(form);
|
const data = new FormData(form);
|
||||||
@@ -68,15 +53,15 @@
|
|||||||
<button type="submit">Create friend</button>
|
<button type="submit">Create friend</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{#if error}
|
{#if error || $friendsListenerError}
|
||||||
<p>{error}</p>
|
<p>{error || $friendsListenerError}</p>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if friends.length === 0}
|
{#if $friends.length === 0}
|
||||||
<p>No friends saved.</p>
|
<p>No friends saved.</p>
|
||||||
{:else}
|
{:else}
|
||||||
<ul>
|
<ul>
|
||||||
{#each friends as friend (friend.id)}
|
{#each $friends as friend (friend.id)}
|
||||||
<li>
|
<li>
|
||||||
<span>{friend.displayName} ({friend.id})</span>
|
<span>{friend.displayName} ({friend.id})</span>
|
||||||
<button type="button" onclick={() => deleteFriend(friend.id)}>Delete</button>
|
<button type="button" onclick={() => deleteFriend(friend.id)}>Delete</button>
|
||||||
|
|||||||
@@ -1,28 +1,15 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount } from "svelte";
|
|
||||||
import {
|
import {
|
||||||
commands,
|
liveMetadata,
|
||||||
events,
|
liveMetadataListenerError,
|
||||||
type AppMeta,
|
} from "$lib/listeners/live-metadata";
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
function liveUserIds() {
|
function liveUserIds() {
|
||||||
return [
|
return [
|
||||||
...new Set([
|
...new Set([
|
||||||
localId,
|
$liveMetadata.localId,
|
||||||
...Object.keys(cursorPositions),
|
...Object.keys($liveMetadata.cursorPositions),
|
||||||
...foregroundApps.keys(),
|
...$liveMetadata.foregroundApps.keys(),
|
||||||
]),
|
]),
|
||||||
].filter(Boolean);
|
].filter(Boolean);
|
||||||
}
|
}
|
||||||
@@ -30,69 +17,21 @@
|
|||||||
function compactId(id: string) {
|
function compactId(id: string) {
|
||||||
return id.length > 16 ? `${id.slice(0, 8)}…${id.slice(-6)}` : id;
|
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>
|
</script>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<h1>Live metadata</h1>
|
<h1>Live metadata</h1>
|
||||||
|
|
||||||
{#if error}
|
{#if $liveMetadataListenerError}
|
||||||
<p>{error}</p>
|
<p>{$liveMetadataListenerError}</p>
|
||||||
{:else if liveUserIds().length === 0}
|
{:else if liveUserIds().length === 0}
|
||||||
<p>Waiting for live metadata...</p>
|
<p>Waiting for live metadata...</p>
|
||||||
{:else}
|
{:else}
|
||||||
{#each liveUserIds() as userId (userId)}
|
{#each liveUserIds() as userId (userId)}
|
||||||
{@const cursor = cursorPositions[userId]}
|
{@const cursor = $liveMetadata.cursorPositions[userId]}
|
||||||
{@const foregroundApp = foregroundApps.get(userId)}
|
{@const foregroundApp = $liveMetadata.foregroundApps.get(userId)}
|
||||||
<article>
|
<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>
|
<p title={userId}>ID: {compactId(userId)}</p>
|
||||||
|
|
||||||
<h3>Cursor</h3>
|
<h3>Cursor</h3>
|
||||||
|
|||||||
@@ -1,39 +1,11 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount } from "svelte";
|
import { commands } from "$lib/bindings";
|
||||||
import { commands, events, type User } from "$lib/bindings";
|
import { profile, profileListenerError } from "$lib/listeners/profile";
|
||||||
|
|
||||||
let profile: User | null = null;
|
|
||||||
let displayName = "";
|
let displayName = "";
|
||||||
let error = "";
|
let error = "";
|
||||||
|
|
||||||
onMount(() => {
|
$: displayName = $profile?.displayName ?? "";
|
||||||
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?.();
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
async function updateProfile(event: SubmitEvent) {
|
async function updateProfile(event: SubmitEvent) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -50,8 +22,8 @@
|
|||||||
<section>
|
<section>
|
||||||
<h1>Profile</h1>
|
<h1>Profile</h1>
|
||||||
|
|
||||||
{#if profile}
|
{#if $profile}
|
||||||
<p>Public key: {profile.id}</p>
|
<p>Public key: {$profile.id}</p>
|
||||||
{:else}
|
{:else}
|
||||||
<p>Loading profile...</p>
|
<p>Loading profile...</p>
|
||||||
{/if}
|
{/if}
|
||||||
@@ -64,7 +36,7 @@
|
|||||||
<button type="submit">Save profile</button>
|
<button type="submit">Save profile</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{#if error}
|
{#if error || $profileListenerError}
|
||||||
<p>{error}</p>
|
<p>{error || $profileListenerError}</p>
|
||||||
{/if}
|
{/if}
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -1,25 +1,10 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount } from "svelte";
|
import { commands, type RemoteInput } from "$lib/bindings";
|
||||||
import { commands, events, type Remote, type RemoteInput } from "$lib/bindings";
|
import { remotes, remotesListenerError } from "$lib/listeners/remotes";
|
||||||
|
|
||||||
let remotes: Remote[] = [];
|
|
||||||
let editingId: string | null = null;
|
let editingId: string | null = null;
|
||||||
let error = "";
|
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 {
|
function remoteInput(form: HTMLFormElement): RemoteInput {
|
||||||
const data = new FormData(form);
|
const data = new FormData(form);
|
||||||
const name = String(data.get("name") ?? "").trim();
|
const name = String(data.get("name") ?? "").trim();
|
||||||
@@ -98,15 +83,15 @@
|
|||||||
<button type="submit">Create remote</button>
|
<button type="submit">Create remote</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{#if error}
|
{#if error || $remotesListenerError}
|
||||||
<p aria-live="polite">{error}</p>
|
<p aria-live="polite">{error || $remotesListenerError}</p>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if remotes.length === 0}
|
{#if $remotes.length === 0}
|
||||||
<p>No remotes saved.</p>
|
<p>No remotes saved.</p>
|
||||||
{:else}
|
{:else}
|
||||||
<ul>
|
<ul>
|
||||||
{#each remotes as remote (remote.id)}
|
{#each $remotes as remote (remote.id)}
|
||||||
<li>
|
<li>
|
||||||
{#if editingId === remote.id}
|
{#if editingId === remote.id}
|
||||||
<form onsubmit={(event) => updateRemote(event, 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>
|
<script>
|
||||||
import { browser } from "$app/environment";
|
import { browser } from "$app/environment";
|
||||||
|
import { onMount } from "svelte";
|
||||||
|
import { initAppListeners } from "$lib/listeners";
|
||||||
import "../app.css";
|
import "../app.css";
|
||||||
|
|
||||||
let { children } = $props();
|
let { children } = $props();
|
||||||
|
|
||||||
|
onMount(initAppListeners);
|
||||||
|
|
||||||
if (browser) {
|
if (browser) {
|
||||||
document.addEventListener("contextmenu", (e) => {
|
document.addEventListener("contextmenu", (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|||||||
Reference in New Issue
Block a user