friends connection status system
This commit is contained in:
@@ -44,6 +44,9 @@ async getPublicKey() : Promise<string> {
|
||||
async listStatuses() : Promise<ConnectionStatus[]> {
|
||||
return await TAURI_INVOKE("list_statuses");
|
||||
},
|
||||
async listFriendStatuses() : Promise<string[]> {
|
||||
return await TAURI_INVOKE("list_friend_statuses");
|
||||
},
|
||||
async pickAndSendImage(recipientId: string) : Promise<boolean> {
|
||||
return await TAURI_INVOKE("pick_and_send_image", { recipientId });
|
||||
},
|
||||
@@ -66,6 +69,7 @@ cursorPositionChanged: CursorPositionChanged,
|
||||
foregroundAppChanged: ForegroundAppChanged,
|
||||
friendForegroundAppChanged: FriendForegroundAppChanged,
|
||||
friendInteractionReceived: FriendInteractionReceived,
|
||||
friendStatusesChanged: FriendStatusesChanged,
|
||||
friendsChanged: FriendsChanged,
|
||||
networkStatusChanged: NetworkStatusChanged,
|
||||
profileChanged: ProfileChanged,
|
||||
@@ -75,6 +79,7 @@ cursorPositionChanged: "cursor-position-changed",
|
||||
foregroundAppChanged: "foreground-app-changed",
|
||||
friendForegroundAppChanged: "friend-foreground-app-changed",
|
||||
friendInteractionReceived: "friend-interaction-received",
|
||||
friendStatusesChanged: "friend-statuses-changed",
|
||||
friendsChanged: "friends-changed",
|
||||
networkStatusChanged: "network-status-changed",
|
||||
profileChanged: "profile-changed",
|
||||
@@ -107,6 +112,7 @@ mapped: CursorPosition }
|
||||
export type ForegroundAppChanged = { meta: AppMeta }
|
||||
export type FriendForegroundAppChanged = { friendId: string; meta: AppMeta }
|
||||
export type FriendInteractionReceived = { interactionId: string; friendId: string; content: InteractionContent }
|
||||
export type FriendStatusesChanged = { friendIds: string[] }
|
||||
export type FriendsChanged = { friends: User[] }
|
||||
export type InteractionContent = { type: "text"; text: string } | { type: "wave" } | { type: "image"; mediaType: string; data: string }
|
||||
export type NetworkStatusChanged = { statuses: ConnectionStatus[] }
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
<script lang="ts">
|
||||
import {
|
||||
friendStatusesListenerError,
|
||||
onlineFriendIds,
|
||||
} from "$lib/listeners/friend-statuses";
|
||||
import { friends, friendsListenerError } from "$lib/listeners/friends";
|
||||
</script>
|
||||
|
||||
<section>
|
||||
<h1>Friend statuses</h1>
|
||||
|
||||
{#if $friendsListenerError || $friendStatusesListenerError}
|
||||
<p aria-live="polite">
|
||||
{$friendsListenerError || $friendStatusesListenerError}
|
||||
</p>
|
||||
{:else if $friends.length === 0}
|
||||
<p>No friends configured.</p>
|
||||
{:else}
|
||||
<ul aria-live="polite">
|
||||
{#each $friends as friend (friend.id)}
|
||||
{@const online = $onlineFriendIds.has(friend.id)}
|
||||
<li>
|
||||
<strong>{friend.displayName}</strong>: {online ? "Online" : "Offline"}
|
||||
<small>({friend.id})</small>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
{/if}
|
||||
</section>
|
||||
@@ -0,0 +1,31 @@
|
||||
import { writable } from "svelte/store";
|
||||
import { commands, events } from "$lib/bindings";
|
||||
import { removeFriendForegroundApps } from "./live-metadata";
|
||||
|
||||
export const onlineFriendIds = writable<Set<string>>(new Set());
|
||||
export const friendStatusesListenerError = writable("");
|
||||
|
||||
export async function initFriendStatusesListener() {
|
||||
let current = new Set<string>();
|
||||
|
||||
const apply = (friendIds: string[]) => {
|
||||
const next = new Set(friendIds);
|
||||
const wentOffline = [...current].filter((friendId) => !next.has(friendId));
|
||||
current = next;
|
||||
onlineFriendIds.set(next);
|
||||
|
||||
removeFriendForegroundApps(wentOffline);
|
||||
};
|
||||
|
||||
const unlisten = await events.friendStatusesChanged.listen((event) => {
|
||||
apply(event.payload.friendIds);
|
||||
});
|
||||
|
||||
try {
|
||||
apply(await commands.listFriendStatuses());
|
||||
} catch (error) {
|
||||
friendStatusesListenerError.set(String(error));
|
||||
}
|
||||
|
||||
return unlisten;
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import { initConnectionStatusesListener } from "./connection-status";
|
||||
import { initFriendStatusesListener } from "./friend-statuses";
|
||||
import { initFriendsListener } from "./friends";
|
||||
import { initInteractionListener } from "./interactions";
|
||||
import { initLiveMetadataListeners } from "./live-metadata";
|
||||
@@ -16,6 +17,7 @@ export function initAppListeners(): Unlisten {
|
||||
initRemotesListener(),
|
||||
initProfileListener(),
|
||||
initConnectionStatusesListener(),
|
||||
initFriendStatusesListener(),
|
||||
initLiveMetadataListeners(),
|
||||
initInteractionListener(),
|
||||
])
|
||||
|
||||
@@ -19,6 +19,17 @@ export const liveMetadata = writable<LiveMetadata>({
|
||||
});
|
||||
export const liveMetadataListenerError = writable("");
|
||||
|
||||
export function removeFriendForegroundApps(friendIds: string[]) {
|
||||
if (friendIds.length === 0) return;
|
||||
const removed = new Set(friendIds);
|
||||
liveMetadata.update((metadata) => ({
|
||||
...metadata,
|
||||
foregroundApps: new Map(
|
||||
[...metadata.foregroundApps].filter(([userId]) => !removed.has(userId)),
|
||||
),
|
||||
}));
|
||||
}
|
||||
|
||||
export async function initLiveMetadataListeners() {
|
||||
let localId = "";
|
||||
let pendingLocalForegroundApp: AppMeta | null = null;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script>
|
||||
import FriendsList from "$lib/components/friends-list.svelte";
|
||||
import FriendStatuses from "$lib/components/friend-statuses.svelte";
|
||||
import ConnectionStatus from "$lib/components/connection-status.svelte";
|
||||
import Profile from "$lib/components/profile.svelte";
|
||||
import RemotesList from "$lib/components/remotes-list.svelte";
|
||||
@@ -13,6 +14,9 @@
|
||||
<div>
|
||||
<FriendsList />
|
||||
</div>
|
||||
<div>
|
||||
<FriendStatuses />
|
||||
</div>
|
||||
<div>
|
||||
<RemotesList />
|
||||
</div>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { onMount } from "svelte";
|
||||
import Popover from "$lib/components/popover.svelte";
|
||||
import { friends } from "$lib/listeners/friends";
|
||||
import { onlineFriendIds } from "$lib/listeners/friend-statuses";
|
||||
import { incomingInteraction } from "$lib/listeners/interactions";
|
||||
import { liveMetadata } from "$lib/listeners/live-metadata";
|
||||
import { profile } from "$lib/listeners/profile";
|
||||
@@ -28,6 +29,18 @@
|
||||
return () => window.clearTimeout(timer);
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
if (
|
||||
selectedUserId &&
|
||||
selectedUserId !== $liveMetadata.localId &&
|
||||
!$onlineFriendIds.has(selectedUserId)
|
||||
) {
|
||||
selectedUserId = null;
|
||||
selectedUserX = null;
|
||||
lockedPopoverUserId = null;
|
||||
}
|
||||
});
|
||||
|
||||
function displayName(userId: string) {
|
||||
return $profile?.id === userId
|
||||
? $profile.displayName
|
||||
@@ -65,7 +78,7 @@
|
||||
{@const popoverId = `scene-user-${index}`}
|
||||
{@const interaction =
|
||||
$incomingInteraction?.friendId === userId ? $incomingInteraction : null}
|
||||
{#if cursor}
|
||||
{#if cursor && (userId === $liveMetadata.localId || $onlineFriendIds.has(userId))}
|
||||
{@const renderedX =
|
||||
selectedUserId === userId ? selectedUserX : cursor.mapped.x}
|
||||
<div
|
||||
|
||||
Reference in New Issue
Block a user