Skip to content

Commit 8f73f14

Browse files
committed
feat(voip): auto-show controls on call state changes
Show controls automatically when stateChange, trackStateChange events fire or when toggling focus, so users never miss important state updates.
1 parent 7f498a3 commit 8f73f14

2 files changed

Lines changed: 42 additions & 6 deletions

File tree

app/lib/services/voip/useCallStore.test.ts

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jest.mock('react-native-incall-manager', () => ({
1919
setForceSpeakerphoneOn: jest.fn()
2020
}));
2121

22-
function createMockCall(callId: string): IClientMediaCall {
22+
function createMockCall(callId: string) {
2323
const listeners: Record<string, Set<(...args: unknown[]) => void>> = {};
2424
const emitter = {
2525
on: (ev: string, fn: (...args: unknown[]) => void) => {
@@ -30,7 +30,10 @@ function createMockCall(callId: string): IClientMediaCall {
3030
listeners[ev]?.delete(fn);
3131
}
3232
};
33-
return {
33+
const emit = (ev: string) => {
34+
listeners[ev]?.forEach(fn => fn());
35+
};
36+
const call = {
3437
callId,
3538
state: 'active',
3639
muted: false,
@@ -48,6 +51,7 @@ function createMockCall(callId: string): IClientMediaCall {
4851
accept: jest.fn(),
4952
reject: jest.fn()
5053
} as unknown as IClientMediaCall;
54+
return { call, emit };
5155
}
5256

5357
describe('useCallStore controlsVisible', () => {
@@ -74,6 +78,37 @@ describe('useCallStore controlsVisible', () => {
7478
expect(useCallStore.getState().controlsVisible).toBe(true);
7579
});
7680

81+
it('auto-shows controls on stateChange event', () => {
82+
const { call, emit } = createMockCall('c1');
83+
useCallStore.getState().setCall(call);
84+
useCallStore.getState().toggleControlsVisible();
85+
expect(useCallStore.getState().controlsVisible).toBe(false);
86+
87+
emit('stateChange');
88+
89+
expect(useCallStore.getState().controlsVisible).toBe(true);
90+
});
91+
92+
it('auto-shows controls on trackStateChange event', () => {
93+
const { call, emit } = createMockCall('c2');
94+
useCallStore.getState().setCall(call);
95+
useCallStore.getState().toggleControlsVisible();
96+
expect(useCallStore.getState().controlsVisible).toBe(false);
97+
98+
emit('trackStateChange');
99+
100+
expect(useCallStore.getState().controlsVisible).toBe(true);
101+
});
102+
103+
it('toggleFocus always shows controls', () => {
104+
useCallStore.getState().toggleControlsVisible();
105+
expect(useCallStore.getState().controlsVisible).toBe(false);
106+
107+
useCallStore.getState().toggleFocus();
108+
109+
expect(useCallStore.getState().controlsVisible).toBe(true);
110+
});
111+
77112
it('reset restores controlsVisible to true', () => {
78113
useCallStore.getState().toggleControlsVisible();
79114
expect(useCallStore.getState().controlsVisible).toBe(false);
@@ -136,7 +171,7 @@ describe('useCallStore native accepted + stale timer', () => {
136171

137172
it('setCall clears native id and cancels stale timer so advance does not clear bound call context', () => {
138173
useCallStore.getState().setNativeAcceptedCallId('x');
139-
useCallStore.getState().setCall(createMockCall('x'));
174+
useCallStore.getState().setCall(createMockCall('x').call);
140175
jest.advanceTimersByTime(15_000);
141176
expect(useCallStore.getState().call).not.toBeNull();
142177
expect(useCallStore.getState().nativeAcceptedCallId).toBeNull();

app/lib/services/voip/useCallStore.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ export const useCallStore = create<CallStore>((set, get) => ({
163163
if (!currentCall) return;
164164

165165
const newState = currentCall.state;
166-
set({ callState: newState });
166+
set({ callState: newState, controlsVisible: true });
167167

168168
// Set start time when call becomes active
169169
if (newState === 'active' && !get().callStartTime) {
@@ -179,7 +179,8 @@ export const useCallStore = create<CallStore>((set, get) => ({
179179
isMuted: currentCall.muted,
180180
isOnHold: currentCall.held,
181181
remoteMute: currentCall.remoteMute,
182-
remoteHeld: currentCall.remoteHeld
182+
remoteHeld: currentCall.remoteHeld,
183+
controlsVisible: true
183184
});
184185
};
185186

@@ -240,7 +241,7 @@ export const useCallStore = create<CallStore>((set, get) => ({
240241

241242
toggleFocus: () => {
242243
const isFocused = get().focused;
243-
set({ focused: !isFocused });
244+
set({ focused: !isFocused, controlsVisible: true });
244245
if (isFocused) {
245246
Navigation.back();
246247
} else {

0 commit comments

Comments
 (0)