(feat): improve mobile cal ui a bit
All checks were successful
/ build-web (push) Successful in 7m40s
/ build-desktop (linux) (push) Successful in 12m10s
/ build-mobile (push) Successful in 19m34s
/ release (push) Successful in 3m31s

(feat): add popout for call ui on mobile
(fix): fix cache and profile avatar upload stuff
This commit is contained in:
Alois 2026-07-31 22:17:08 +02:00
commit b5ce3c554d
Signed by: alois
SSH key fingerprint: SHA256:GBzT2DXvAuGV9XIV5W3WrzVpjU54FThmxHXdbz95J24
14 changed files with 443 additions and 155 deletions

View file

@ -2,11 +2,13 @@ import { create } from "zustand";
type SpeakingState = {
speakingParticipantIds: Set<number>;
lastSpeakingParticipantId: number | null;
micGated: boolean;
};
const useSpeakingState = create<SpeakingState>(() => ({
speakingParticipantIds: new Set(),
lastSpeakingParticipantId: null,
micGated: false,
}));
@ -20,10 +22,19 @@ export function clearSpeakingParticipants() {
export function removeSpeakingParticipant(participantId: number) {
useSpeakingState.setState((state) => {
if (!state.speakingParticipantIds.has(participantId)) return state;
const wasSpeaking = state.speakingParticipantIds.has(participantId);
const wasLastSpeaking = state.lastSpeakingParticipantId === participantId;
if (!wasSpeaking && !wasLastSpeaking) return state;
const next = new Set(state.speakingParticipantIds);
next.delete(participantId);
return { speakingParticipantIds: next };
return {
speakingParticipantIds: next,
lastSpeakingParticipantId: wasLastSpeaking
? null
: state.lastSpeakingParticipantId,
};
});
}
@ -31,11 +42,13 @@ export function updateSpeakingParticipants(changed: Map<number, boolean>) {
useSpeakingState.setState((state) => {
let hasDiff = false;
const next = new Set(state.speakingParticipantIds);
let lastSpeakingParticipantId = state.lastSpeakingParticipantId;
for (const [id, speaking] of changed) {
if (speaking) {
if (!next.has(id)) {
next.add(id);
lastSpeakingParticipantId = id;
hasDiff = true;
}
} else if (next.has(id)) {
@ -44,10 +57,16 @@ export function updateSpeakingParticipants(changed: Map<number, boolean>) {
}
}
return hasDiff ? { speakingParticipantIds: next } : state;
return hasDiff
? { speakingParticipantIds: next, lastSpeakingParticipantId }
: state;
});
}
export function useLastSpeakingParticipantId(): number | null {
return useSpeakingState((state) => state.lastSpeakingParticipantId);
}
export function useIsSpeaking(participantId: number): boolean {
return useSpeakingState((state) =>
state.speakingParticipantIds.has(participantId),