resolve live data on initial load
This commit is contained in:
@@ -50,6 +50,9 @@ async listFriendStatuses() : Promise<string[]> {
|
||||
async resolveFriendDisplayName(userId: string) : Promise<string | null> {
|
||||
return await TAURI_INVOKE("resolve_friend_display_name", { userId });
|
||||
},
|
||||
async listLiveData() : Promise<LiveDataSnapshot> {
|
||||
return await TAURI_INVOKE("list_live_data");
|
||||
},
|
||||
async resolveSkin(userId: string, skinHash: string) : Promise<string | null> {
|
||||
return await TAURI_INVOKE("resolve_skin", { userId, skinHash });
|
||||
},
|
||||
@@ -142,6 +145,7 @@ export type FriendInteractionReceived = { interactionId: string; friendId: strin
|
||||
export type FriendStatusesChanged = { friendIds: string[] }
|
||||
export type FriendsChanged = { friends: Friend[] }
|
||||
export type InteractionContent = { type: "text"; text: string } | { type: "wave" } | { type: "image"; mediaType: string; data: string }
|
||||
export type LiveDataSnapshot = { cursorPositions: Partial<{ [key in string]: CursorPositions }>; foregroundApps: Partial<{ [key in string]: AppMeta }> }
|
||||
export type NetworkStatusChanged = { statuses: ConnectionStatus[] }
|
||||
export type ProfileChanged = { profile: User }
|
||||
export type PuppetMovementMode = "free" | "bottom"
|
||||
|
||||
@@ -1,20 +1,15 @@
|
||||
import { writable } from "svelte/store";
|
||||
import { commands, events } from "$lib/bindings";
|
||||
import { removeFriendForegroundApps } from "./live-metadata";
|
||||
import { retainOnlineForegroundApps } 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);
|
||||
retainOnlineForegroundApps(next);
|
||||
};
|
||||
|
||||
const unlisten = await events.friendStatusesChanged.listen((event) => {
|
||||
|
||||
@@ -10,17 +10,29 @@ import { initSceneConfigurationListener } from "./scene-configuration";
|
||||
|
||||
type Unlisten = () => void;
|
||||
|
||||
async function initPresenceListeners(): Promise<Unlisten> {
|
||||
const unlistenLiveMetadata = await initLiveMetadataListeners();
|
||||
try {
|
||||
const unlistenFriendStatuses = await initFriendStatusesListener();
|
||||
return () => {
|
||||
unlistenFriendStatuses();
|
||||
unlistenLiveMetadata();
|
||||
};
|
||||
} catch (error) {
|
||||
unlistenLiveMetadata();
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export function initAppListeners(): Unlisten {
|
||||
let disposed = false;
|
||||
let unlisteners: Unlisten[] = [];
|
||||
|
||||
Promise.allSettled([
|
||||
initFriendsListener(),
|
||||
initRemotesListener(),
|
||||
initProfileListener(),
|
||||
initConnectionStatusesListener(),
|
||||
initFriendStatusesListener(),
|
||||
initLiveMetadataListeners(),
|
||||
initPresenceListeners(),
|
||||
initInteractionListener(),
|
||||
initPuppetStatesListener(),
|
||||
initSceneConfigurationListener(),
|
||||
|
||||
@@ -19,20 +19,24 @@ export const liveMetadata = writable<LiveMetadata>({
|
||||
});
|
||||
export const liveMetadataListenerError = writable("");
|
||||
|
||||
export function removeFriendForegroundApps(friendIds: string[]) {
|
||||
if (friendIds.length === 0) return;
|
||||
const removed = new Set(friendIds);
|
||||
export function retainOnlineForegroundApps(onlineFriendIds: Set<string>) {
|
||||
liveMetadata.update((metadata) => ({
|
||||
...metadata,
|
||||
foregroundApps: new Map(
|
||||
[...metadata.foregroundApps].filter(([userId]) => !removed.has(userId)),
|
||||
[...metadata.foregroundApps].filter(
|
||||
([userId]) =>
|
||||
userId === metadata.localId || onlineFriendIds.has(userId),
|
||||
),
|
||||
),
|
||||
}));
|
||||
}
|
||||
|
||||
export async function initLiveMetadataListeners() {
|
||||
let localId = "";
|
||||
let initializing = true;
|
||||
let pendingCursorPositions: LiveMetadata["cursorPositions"] | null = null;
|
||||
let pendingLocalForegroundApp: AppMeta | null = null;
|
||||
const pendingFriendForegroundApps = new Map<string, AppMeta>();
|
||||
|
||||
const updateForegroundApp = (userId: string, meta: AppMeta) => {
|
||||
liveMetadata.update((current) => ({
|
||||
@@ -41,34 +45,76 @@ export async function initLiveMetadataListeners() {
|
||||
}));
|
||||
};
|
||||
|
||||
const applyPendingUpdates = () => {
|
||||
const cursorPositions = pendingCursorPositions;
|
||||
if (cursorPositions) {
|
||||
liveMetadata.update((current) => ({ ...current, cursorPositions }));
|
||||
pendingCursorPositions = null;
|
||||
}
|
||||
if (localId && pendingLocalForegroundApp) {
|
||||
updateForegroundApp(localId, pendingLocalForegroundApp);
|
||||
pendingLocalForegroundApp = null;
|
||||
}
|
||||
pendingFriendForegroundApps.forEach((meta, friendId) => {
|
||||
updateForegroundApp(friendId, meta);
|
||||
});
|
||||
pendingFriendForegroundApps.clear();
|
||||
};
|
||||
|
||||
const unlisteners = await Promise.all([
|
||||
events.cursorPositionChanged.listen((event) => {
|
||||
if (initializing) {
|
||||
pendingCursorPositions = event.payload.positions;
|
||||
return;
|
||||
}
|
||||
liveMetadata.update((current) => ({
|
||||
...current,
|
||||
cursorPositions: event.payload.positions,
|
||||
}));
|
||||
}),
|
||||
events.foregroundAppChanged.listen((event) => {
|
||||
if (localId) {
|
||||
if (!initializing && localId) {
|
||||
updateForegroundApp(localId, event.payload.meta);
|
||||
} else {
|
||||
pendingLocalForegroundApp = event.payload.meta;
|
||||
}
|
||||
}),
|
||||
events.friendForegroundAppChanged.listen((event) => {
|
||||
updateForegroundApp(event.payload.friendId, event.payload.meta);
|
||||
if (initializing) {
|
||||
pendingFriendForegroundApps.set(
|
||||
event.payload.friendId,
|
||||
event.payload.meta,
|
||||
);
|
||||
} else {
|
||||
updateForegroundApp(event.payload.friendId, event.payload.meta);
|
||||
}
|
||||
}),
|
||||
]);
|
||||
|
||||
try {
|
||||
localId = await commands.getPublicKey();
|
||||
liveMetadata.update((current) => ({ ...current, localId }));
|
||||
|
||||
if (pendingLocalForegroundApp) {
|
||||
updateForegroundApp(localId, pendingLocalForegroundApp);
|
||||
pendingLocalForegroundApp = null;
|
||||
}
|
||||
const [snapshot] = await Promise.all([
|
||||
commands.listLiveData(),
|
||||
commands.getPublicKey().then((resolvedLocalId) => {
|
||||
localId = resolvedLocalId;
|
||||
}),
|
||||
]);
|
||||
const foregroundApps = new Map<string, AppMeta>();
|
||||
Object.entries(snapshot.foregroundApps).forEach(([userId, meta]) => {
|
||||
if (meta) foregroundApps.set(userId, meta);
|
||||
});
|
||||
liveMetadata.set({
|
||||
localId,
|
||||
cursorPositions: snapshot.cursorPositions,
|
||||
foregroundApps,
|
||||
});
|
||||
initializing = false;
|
||||
applyPendingUpdates();
|
||||
} catch (error) {
|
||||
initializing = false;
|
||||
if (localId) {
|
||||
liveMetadata.update((current) => ({ ...current, localId }));
|
||||
}
|
||||
applyPendingUpdates();
|
||||
liveMetadataListenerError.set(String(error));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user