/** * call-groupCall — Self-observing group call plugin for WeChat Mini Program. * * The plugin listens to call state and group-call flag changes through the uni * global event bus. When a group call enters CALLING or CONNECTED status, it * navigates to the GroupCallView page; when the call returns to IDLE, it * navigates back. * * The host (TUICallService) publishes events on the same bus — neither side * imports from the other. The event name convention is the only contract. * * @example * ```ts * import { useGroupCallPlugin } from '../plugin/groupCall'; * TUICallKitAPI.registerPlugin(useGroupCallPlugin()); * ``` */ import { GROUP_CALL_EVENTS, STATUS_IDLE } from './store'; export { GROUP_CALL_EVENTS } from './store'; // ====================== Plugin State ====================== /** Latest callStatus received, tracked locally. */ let currentCallStatus = ''; /** Latest isGroup flag, tracked locally. */ let currentIsGroup = false; /** Whether the group call page is currently being navigated to. */ let isNavigating = false; // ====================== Page Navigation ====================== /** * Navigate to the GroupCallView page. * Uses the global page path configured via wx.$globalGroupCallPagePath. */ function navigateToGroupCallPage(): void { if (isNavigating) return; const targetPagePath = (wx as any).$globalGroupCallPagePath; if (!targetPagePath) { console.warn('[call-groupCall] wx.$globalGroupCallPagePath is not set, cannot navigate to group call page'); return; } // Check if we are already on the target page. // @ts-ignore const pages = getCurrentPages(); const currentRoute = pages.length > 0 ? pages[pages.length - 1].route : ''; if (currentRoute === targetPagePath) return; isNavigating = true; wx.navigateTo({ url: `/${targetPagePath}`, success: () => { isNavigating = false; // If the call has already ended by the time the page opened, navigate back. if (currentCallStatus === STATUS_IDLE) { navigateBackFromGroupCallPage(); } }, fail: (err: any) => { console.error('[call-groupCall] navigateTo fail:', err); isNavigating = false; }, }); } /** * Navigate back from the GroupCallView page when the call ends. */ function navigateBackFromGroupCallPage(): void { // @ts-ignore const pages = getCurrentPages(); const targetPagePath = (wx as any).$globalGroupCallPagePath; if (!targetPagePath) return; const currentRoute = pages.length > 0 ? pages[pages.length - 1].route : ''; if (currentRoute === targetPagePath) { wx.navigateBack({ delta: 1 }); } } // ====================== Uni Event Handlers ====================== function handleStatusChange(callStatus: string): void { try { currentCallStatus = callStatus; // Only react to group calls. if (!currentIsGroup) return; if (callStatus !== STATUS_IDLE) { // Call is active (CALLING or CONNECTED): navigate to GroupCallView. navigateToGroupCallPage(); } else { // Call is IDLE: navigate back from GroupCallView. navigateBackFromGroupCallPage(); } } catch (e) { console.warn('[call-groupCall] handleStatusChange error:', e); } } function handleIsGroupChange(isGroup: boolean): void { try { currentIsGroup = !!isGroup; // If we just switched to a group call and the call is already active, // navigate to GroupCallView immediately. if (isGroup && currentCallStatus !== STATUS_IDLE && currentCallStatus !== '') { navigateToGroupCallPage(); } } catch (e) { console.warn('[call-groupCall] handleIsGroupChange error:', e); } } // Wrapped callbacks stored so we can unregister them later. let _onStatus: ((v: any) => void) | null = null; let _onIsGroup: ((v: any) => void) | null = null; // ====================== Plugin Factory ====================== let _instance: Record | null = null; /** * Create a group call plugin instance (singleton). * * The plugin connects to the uni global event bus internally — no arguments * required. TUICallService publishes call state changes on the same bus; * neither side imports anything from the other. * * @returns A plugin object to pass to {@code TUICallKitAPI.registerPlugin()}. * The host MUST NOT call any methods on the returned object. */ export function useGroupCallPlugin(): Record { if (_instance) { console.warn('[call-groupCall] useGroupCallPlugin was already called, returning existing instance'); return _instance; } _onStatus = (v: any) => handleStatusChange(v); _onIsGroup = (v: any) => handleIsGroupChange(v); uni.$on(GROUP_CALL_EVENTS.STATUS_CHANGED, _onStatus); uni.$on(GROUP_CALL_EVENTS.IS_GROUP_CHANGED, _onIsGroup); currentCallStatus = ''; currentIsGroup = false; return _instance = { // Plugin identifier used by the host's unified registerPlugin() to // dispatch this instance to the correct slot. name: 'groupCall', destroy() { if (_onStatus) uni.$off(GROUP_CALL_EVENTS.STATUS_CHANGED, _onStatus); if (_onIsGroup) uni.$off(GROUP_CALL_EVENTS.IS_GROUP_CHANGED, _onIsGroup); _onStatus = null; _onIsGroup = null; _instance = null; currentCallStatus = ''; currentIsGroup = false; isNavigating = false; }, }; }