Skip to content

Commit 2333ca4

Browse files
committed
added: event management and first emitted event 'status'
1 parent 6a9221c commit 2333ca4

File tree

10 files changed

+89
-38
lines changed

10 files changed

+89
-38
lines changed

index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ export { default as HxMeeting } from './src/components/HxMeeting.vue'
22
export { default as HxToolbar } from './src/components/toolbar/HxToolbar.vue'
33
export { default as HxSelectButton } from './src/components/toolbar/HxSelectButton.vue'
44

5+
export type { HxMeetingStatus } from './src/types/conference.ts'
6+
57
// export { default as HxRoundButton } from './src/components/HxRoundButton.vue'
68
// export type { HxRoundButtonProps } from './src/components/HxRoundButton.vue'
79

src/App.vue

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,19 @@
66

77
<script setup lang="ts">
88
import type {HxMeetingProps} from "./components/HxMeeting.vue";
9+
import type {HxMeetingStatus} from "@/types/conference.ts";
910
const params = new URLSearchParams(window.location.search)
1011
1112
const meetingProps: HxMeetingProps = {
1213
livekitUrl: params.get("livekitUrl") || import.meta.env.VITE_LIVEKIT_URL,
1314
livekitToken: params.get("livekitToken") || import.meta.env.VITE_LIVEKIT_TOKEN,
1415
extensions: {
1516
'sidebar.info.body': "Hallo"
17+
},
18+
events: {
19+
'status': (status: HxMeetingStatus): void => {
20+
console.log('Listener status changed', status)
21+
}
1622
}
1723
}
1824

src/components/HxMeeting.vue

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -56,36 +56,37 @@ import {
5656
import {useClickSidebarButton, useModal} from "../composable/ui.ts";
5757
import {useThrottleFn} from "@vueuse/core";
5858
import {defineShortcuts2 as defineShortcuts} from "../composable/nuxtui/defineShortcuts2.ts";
59-
import {type ComponentDescriptor, useExtensions} from "../composable/useExtensions.ts";
59+
import {type HxComponentDescriptor, useExtensions} from "../composable/useExtensions.ts";
60+
import {type HxHandler, type HxEvent, useEvents} from "../composable/useEvents.ts";
6061
6162
const { hideSidebar } = useUIState();
6263
const {closeAllModals} = useModal()
6364
6465
export interface HxMeetingProps {
6566
livekitUrl: string,
6667
livekitToken: string,
67-
extensions?: Record<string, string | Ref | ComponentDescriptor>;
68+
extensions?: Record<string, string | Ref | HxComponentDescriptor>;
69+
events?: Partial<Record<HxEvent, HxHandler>>;
6870
}
69-
7071
const props = defineProps<HxMeetingProps>()
7172
72-
// ----------------------------------------------------------
73-
// Extensions
74-
// ----------------------------------------------------------
75-
73+
// ---------------------------------------
74+
// Register extensions
75+
// ---------------------------------------
7676
const { set } = useExtensions();
77-
7877
watch(() => props.extensions, (extensions) => {
79-
console.log("extensions changed", extensions);
80-
if (!extensions) return;
81-
for (const [name, item] of Object.entries(extensions)) set(name, item);
82-
},
83-
{ immediate: true, deep: true }
84-
);
85-
86-
// ----------------------------------------------------------
87-
// ----------------------------------------------------------
88-
// ----------------------------------------------------------
78+
if (!extensions) return;
79+
for (const [name, item] of Object.entries(extensions)) set(name, item);
80+
}, { immediate: true, deep: true });
81+
82+
// ---------------------------------------
83+
// Register event listener
84+
// ---------------------------------------
85+
const { on } = useEvents();
86+
watch(() => props.events, (events) => {
87+
if (!events) return;
88+
for (const [name, item] of Object.entries(events)) on(name as HxEvent, item);
89+
}, { immediate: true, deep: true });
8990
9091
onBeforeMount(() => {
9192
provideLivekitConfig(

src/components/sidebar/HxInfoPanel.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
<span v-if="bodyExtension && (isRef(bodyExtension) || typeof bodyExtension === 'string')">{{ bodyExtension }}</span>
66
<component
77
v-else-if="bodyExtension"
8-
:is="(bodyExtension as ComponentDescriptor).component"
9-
v-bind="(bodyExtension as ComponentDescriptor).props"
8+
:is="(bodyExtension as HxComponentDescriptor).component"
9+
v-bind="(bodyExtension as HxComponentDescriptor).props"
1010
/>
1111

1212
</div>
@@ -41,7 +41,7 @@ import UTooltip from "@nuxt/ui/components/Tooltip.vue";
4141
import UButton from "@nuxt/ui/components/Button.vue";
4242
import {useUIState} from "../../composable/conferenceState.ts";
4343
import HxPanel from "./HxPanel.vue";
44-
import {type ComponentDescriptor, useExtensions} from '../../composable/useExtensions.ts';
44+
import {type HxComponentDescriptor, useExtensions} from '../../composable/useExtensions.ts';
4545
const { sidebarResizing } = useUIState();
4646
4747
const { get } = useExtensions();

src/components/stage/HxStagePanel.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
:layoutStyles="getVideoPositionStyle(idx)"
1111
/>
1212
<HxVideo
13-
v-if="roomConnectStatus === ''"
13+
v-if="roomConnectStatus === 'initialising'"
1414
:idx="0"
1515
:participant="fakeParticipant"
1616
:key="0"
@@ -73,7 +73,7 @@ const getVideoPositionStyle = (index: number): LayoutStyleItem => {
7373
// This function calculates the position of each video in the conference canvas
7474
// Will be called everytime canvasDim or participants change, like a computed property
7575
76-
const total = roomConnectStatus.value === '' ? 1 : participants.value.length;
76+
const total = roomConnectStatus.value === 'initialising' ? 1 : participants.value.length;
7777
if (layout.value === 'grid') {
7878
return calcGridLayout(index, total, canvasDim.value.width, canvasDim.value.height);
7979
} else if (layout.value === 'screenshare') {

src/composable/conferenceActions.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type {HxParticipant, LayoutKey, RoomConnectStatusKey} from "../types/conference";
1+
import type {HxParticipant, LayoutKey, HxMeetingStatus} from "../types/conference";
22
import {useThrottleFn} from '@vueuse/core'
33
import {convertLinksToAnchorTags, escapeHtml} from "../helper/helper";
44
import {defaultLayoutOption, layoutOptions} from "../types/conference";
@@ -23,11 +23,11 @@ import {
2323
export const useEnterConference = async () => {
2424
log.info("Enter conference");
2525
const { roomConnectStatus } = useConferenceState();
26-
roomConnectStatus.value = "";
26+
roomConnectStatus.value = "initialising";
2727
await useConnectLivekit();
2828
};
2929

30-
export const useLeaveConference = async (status: RoomConnectStatusKey = "") => {
30+
export const useLeaveConference = async ( status: HxMeetingStatus = "initialising") => {
3131
log.info("Leave conference");
3232
await useDisconnectLivekit();
3333
const { resetState } = useConferenceState();

src/composable/conferenceState.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
1-
import {type Ref, ref, computed} from "vue"
1+
import {type Ref, ref, computed, watch} from "vue"
22

3-
import type {HxParticipant, ChatMessageUIItem, RoomConnectStatusKey, LayoutKey} from "../types/conference";
3+
import type {HxParticipant, ChatMessageUIItem, HxMeetingStatus, LayoutKey} from "../types/conference";
44
import {exampleNames} from "../helper/example";
55
import {defaultLayoutOption} from "../types/conference";
66
import {log} from "../helper/logger";
77
import {useTrackStore} from "./livekit.ts";
88
import {useLocalHxParticipant} from "./conferenceActions.ts";
9+
import {useEvents} from "./useEvents.ts";
910

1011
// ---------------------------------------------------------------------
1112
// Conference data
1213
// ---------------------------------------------------------------------
13-
const roomConnectStatus: Ref<RoomConnectStatusKey> = ref("");
14+
const roomConnectStatus: Ref<HxMeetingStatus> = ref("initialising");
1415
const microphone: Ref<boolean> = ref(true);
1516
const camera: Ref<boolean> = ref(true);
1617
const loadingCamera: Ref<boolean> = ref(false);
@@ -19,6 +20,11 @@ const participants: Ref<HxParticipant[]> = ref([]);
1920
const messages: Ref<ChatMessageUIItem[]> = ref([]);
2021
const newMessageCount: Ref<number> = ref(0);
2122

23+
const { emit } = useEvents();
24+
watch(roomConnectStatus, async (status) => {
25+
await emit("status", status);
26+
})
27+
2228
export const useConferenceState = () => {
2329

2430
// ---------------------------------------------------------------------
@@ -63,7 +69,7 @@ export const useConferenceState = () => {
6369
const increaseNewMessageCount = () => (newMessageCount.value += 1);
6470
const resetNewMessageCount = () => (newMessageCount.value = 0);
6571

66-
const resetState = (status: RoomConnectStatusKey = "") => {
72+
const resetState = async (status: HxMeetingStatus = "initialising") => {
6773
const { resetTracks } = useTrackStore();
6874
log.info("resetState", status);
6975
resetTracks();

src/composable/useEvents.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import {createLogger} from "../helper/logger";
2+
3+
const log = createLogger('HxMeet:Events')
4+
5+
export type HxEvent = 'status'
6+
export type HxHandler = (payload?: any) => any | Promise<any>;
7+
type EventMap = Map<HxEvent, Set<HxHandler>>;
8+
const listeners: EventMap = new Map();
9+
10+
export function useEvents() {
11+
12+
const on = (event: HxEvent, handler: HxHandler): void => {
13+
if (!listeners.has(event)) listeners.set(event, new Set());
14+
log.info("Register event handler", event)
15+
listeners.get(event)!.add(handler);
16+
}
17+
18+
const off = (event: HxEvent, handler: HxHandler): void => {
19+
log.info("Unregister event handler", event)
20+
listeners.get(event)?.delete(handler);
21+
}
22+
23+
const emit = (event: HxEvent, payload?: any): Promise<any> => {
24+
log.info("Emit event", { event, payload })
25+
const list = Array.from(listeners.get(event) ?? []);
26+
const results = list.map(h => Promise.resolve().then(() => h(payload)));
27+
return Promise.all(results);
28+
}
29+
30+
return {
31+
on, off, emit
32+
};
33+
}

src/composable/useExtensions.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,25 @@
11
import { shallowRef, type Ref, type Component, isRef } from 'vue';
2+
import {createLogger} from "../helper/logger";
23

3-
export type ComponentDescriptor = { component: Component; props?: Record<string, any> };
4-
type ExtensionValue = Ref<string> | ComponentDescriptor;
4+
const log = createLogger('HxMeet:Extensions')
5+
6+
export type HxComponentDescriptor = { component: Component; props?: Record<string, any> };
7+
type ExtensionValue = Ref<string> | HxComponentDescriptor;
58
type ExtensionMap = Map<string, ExtensionValue>;
69
const extensions: ExtensionMap = new Map();
710

811
export function useExtensions() {
912

10-
const set = (name: string, item: string | Ref | ComponentDescriptor) => {
13+
const set = (name: string, item: string | Ref | HxComponentDescriptor) => {
1114
if (typeof item === 'string') {
12-
console.log("set (string)", name, item)
15+
log.info("Set extension (type: string)", name, item)
1316
extensions.set(name, shallowRef<string>(item));
1417
} else if (isRef(item)) {
15-
console.log("set (ref)", name, item)
18+
log.info("Set extension (type: Ref)", name, item)
1619
extensions.set(name, item as Ref);
1720
} else {
18-
console.log("set (comp-descriptor)", name, item)
19-
extensions.set(name, item as ComponentDescriptor);
21+
log.info("Set extension (type: ComponentDescriptor)", name, item)
22+
extensions.set(name, item as HxComponentDescriptor);
2023
}
2124
}
2225

src/types/conference.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export interface LayoutStyleItem {
2020
videoElement: any,
2121
}
2222

23-
export type RoomConnectStatusKey = "" | "connecting" | "connected" | "failed" | "end" | "noDevices";
23+
export type HxMeetingStatus = "initialising" | "connecting" | "connected" | "failed" | "end" | "noDevices";
2424
export type LayoutKey = "circle" | "grid" | "cinema" | "screenshare";
2525
export const layoutOptions: LayoutKey[] = ['circle', 'grid', 'cinema'];
2626
export const defaultLayoutOption: LayoutKey = 'circle';

0 commit comments

Comments
 (0)