Add Chat tab with Julia AI + voice call improvements
- Enable Chat tab (replace Debug) - text chat with Julia AI - Add voice call button in chat header and input area - Add speaker/earpiece toggle in voice-call screen - setAudioOutput() function for switching audio output
This commit is contained in:
parent
6a6c85f7c3
commit
cd9dddda34
@ -46,11 +46,14 @@ export default function TabLayout() {
|
||||
href: null,
|
||||
}}
|
||||
/>
|
||||
{/* Chat hidden for now - testing via debug */}
|
||||
{/* Chat with Julia AI */}
|
||||
<Tabs.Screen
|
||||
name="chat"
|
||||
options={{
|
||||
href: null,
|
||||
title: 'Julia',
|
||||
tabBarIcon: ({ color, size }) => (
|
||||
<Feather name="message-circle" size={22} color={color} />
|
||||
),
|
||||
}}
|
||||
/>
|
||||
{/* Voice tab hidden - using Debug for testing */}
|
||||
@ -69,14 +72,11 @@ export default function TabLayout() {
|
||||
),
|
||||
}}
|
||||
/>
|
||||
{/* Debug tab for testing */}
|
||||
{/* Debug tab hidden */}
|
||||
<Tabs.Screen
|
||||
name="debug"
|
||||
options={{
|
||||
title: 'Debug',
|
||||
tabBarIcon: ({ color, size }) => (
|
||||
<Feather name="code" size={22} color={color} />
|
||||
),
|
||||
href: null,
|
||||
}}
|
||||
/>
|
||||
{/* Hide explore tab */}
|
||||
|
||||
@ -35,6 +35,7 @@ import { AppColors, BorderRadius, FontSizes, Spacing } from '@/constants/theme';
|
||||
import { VOICE_NAME } from '@/services/livekitService';
|
||||
import { useVoiceTranscript } from '@/contexts/VoiceTranscriptContext';
|
||||
import { useLiveKitRoom, ConnectionState } from '@/hooks/useLiveKitRoom';
|
||||
import { setAudioOutput } from '@/utils/audioSession';
|
||||
|
||||
const { width: SCREEN_WIDTH } = Dimensions.get('window');
|
||||
|
||||
@ -47,6 +48,9 @@ export default function VoiceCallScreen() {
|
||||
const [logsMinimized, setLogsMinimized] = React.useState(false);
|
||||
const logsScrollRef = useRef<ScrollView>(null);
|
||||
|
||||
// Speaker/earpiece toggle state
|
||||
const [isSpeakerOn, setIsSpeakerOn] = React.useState(true);
|
||||
|
||||
// LiveKit hook - ALL logic is here
|
||||
const {
|
||||
state,
|
||||
@ -159,6 +163,13 @@ export default function VoiceCallScreen() {
|
||||
router.back();
|
||||
};
|
||||
|
||||
// Toggle speaker/earpiece
|
||||
const handleToggleSpeaker = async () => {
|
||||
const newSpeakerState = !isSpeakerOn;
|
||||
setIsSpeakerOn(newSpeakerState);
|
||||
await setAudioOutput(newSpeakerState);
|
||||
};
|
||||
|
||||
// Copy logs to clipboard
|
||||
const copyLogs = async () => {
|
||||
const logsText = logs.map(l => `[${l.timestamp}] ${l.message}`).join('\n');
|
||||
@ -376,10 +387,18 @@ export default function VoiceCallScreen() {
|
||||
<Ionicons name="call" size={32} color={AppColors.white} />
|
||||
</TouchableOpacity>
|
||||
|
||||
{/* Speaker button (placeholder for future) */}
|
||||
<TouchableOpacity style={styles.controlButton} disabled>
|
||||
<Ionicons name="volume-high" size={28} color={AppColors.white} />
|
||||
<Text style={styles.controlLabel}>Speaker</Text>
|
||||
{/* Speaker/Earpiece toggle */}
|
||||
<TouchableOpacity
|
||||
style={[styles.controlButton, isSpeakerOn && styles.controlButtonActive]}
|
||||
onPress={handleToggleSpeaker}
|
||||
disabled={!isActive}
|
||||
>
|
||||
<Ionicons
|
||||
name={isSpeakerOn ? 'volume-high' : 'ear'}
|
||||
size={28}
|
||||
color={isSpeakerOn ? AppColors.success : AppColors.white}
|
||||
/>
|
||||
<Text style={styles.controlLabel}>{isSpeakerOn ? 'Speaker' : 'Earpiece'}</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
|
||||
@ -145,3 +145,45 @@ export async function reconfigureAudioForPlayback(): Promise<void> {
|
||||
// Don't throw - this is a best-effort operation
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch audio output between speaker and earpiece
|
||||
*
|
||||
* @param useSpeaker - true for speaker, false for earpiece
|
||||
*/
|
||||
export async function setAudioOutput(useSpeaker: boolean): Promise<void> {
|
||||
if (Platform.OS !== 'ios') {
|
||||
console.log('[AudioSession] setAudioOutput - skipping on non-iOS');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[AudioSession] Setting audio output to ${useSpeaker ? 'SPEAKER' : 'EARPIECE'}...`);
|
||||
|
||||
try {
|
||||
const AudioSession = await getAudioSession();
|
||||
if (!AudioSession) {
|
||||
console.error('[AudioSession] Failed to get AudioSession module');
|
||||
return;
|
||||
}
|
||||
|
||||
// Configure audio output
|
||||
await AudioSession.configureAudio({
|
||||
ios: {
|
||||
defaultOutput: useSpeaker ? 'speaker' : 'earpiece',
|
||||
},
|
||||
});
|
||||
|
||||
// Also update the full configuration to ensure it takes effect
|
||||
await AudioSession.setAppleAudioConfiguration({
|
||||
audioCategory: 'playAndRecord',
|
||||
audioCategoryOptions: useSpeaker
|
||||
? ['allowBluetooth', 'allowBluetoothA2DP', 'defaultToSpeaker', 'mixWithOthers']
|
||||
: ['allowBluetooth', 'allowBluetoothA2DP', 'mixWithOthers'],
|
||||
audioMode: 'voiceChat',
|
||||
});
|
||||
|
||||
console.log(`[AudioSession] Audio output set to ${useSpeaker ? 'SPEAKER' : 'EARPIECE'}`);
|
||||
} catch (error) {
|
||||
console.error('[AudioSession] setAudioOutput error:', error);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user