Skip to content

Commit 9e8598d

Browse files
committed
Implement an audio call
1 parent 3805ee9 commit 9e8598d

File tree

6 files changed

+82
-11
lines changed

6 files changed

+82
-11
lines changed

app/src/main/kotlin/io/getstream/whatsappclone/navigation/WhatsAppNavigation.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@ fun NavGraphBuilder.whatsAppHomeNavigation() {
6565
arguments = WhatsAppScreens.VideoCall.navArguments
6666
) {
6767
val callId = it.arguments?.getString(WhatsAppScreens.VideoCall.KEY_CALL_ID) ?: return@composable
68+
val videoCall =
69+
it.arguments?.getBoolean(WhatsAppScreens.VideoCall.KEY_VIDEO_ID) ?: return@composable
6870

69-
WhatsAppVideoCall(id = callId)
71+
WhatsAppVideoCall(id = callId, videoCall = videoCall)
7072
}
7173
}

core/navigation/src/main/kotlin/io/getstream/whatsappclone/navigation/WhatsAppScreens.kt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,19 @@ sealed class WhatsAppScreens(
6262
navArgument("call_id") {
6363
type = NavType.StringType
6464
nullable = false
65+
},
66+
navArgument("video_call") {
67+
type = NavType.BoolType
68+
nullable = false
6569
}
6670
)
6771
) {
6872
const val KEY_CALL_ID = "call_id"
73+
const val KEY_VIDEO_ID = "video_call"
6974

70-
fun createRoute(callId: String) =
71-
name.replace("{${navArguments.first().name}}", callId)
75+
fun createRoute(callId: String, videoCall: Boolean) =
76+
name.replace("{${navArguments[0].name}}", callId)
77+
.replace("{${navArguments[1].name}}", videoCall.toString())
7278
}
7379
}
7480

features/chats/src/main/kotlin/io/getstream/whatsappclone/chats/messages/WhatsAppMessageTopBar.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ fun WhatsAppMessageTopBar(
7070
modifier = Modifier
7171
.size(26.dp)
7272
.clickable {
73-
whatsAppMessagesViewModel.navigateToVideoCall(channelId = channelId)
73+
whatsAppMessagesViewModel.navigateToVideoCall(channelId = channelId, videoCall = true)
7474
},
7575
imageVector = WhatsAppIcons.Video,
7676
tint = MaterialTheme.colorScheme.tertiary,
@@ -80,7 +80,11 @@ fun WhatsAppMessageTopBar(
8080
Spacer(modifier = Modifier.size(16.dp))
8181

8282
Icon(
83-
modifier = Modifier.size(26.dp),
83+
modifier = Modifier
84+
.size(26.dp)
85+
.clickable {
86+
whatsAppMessagesViewModel.navigateToVideoCall(channelId = channelId, videoCall = false)
87+
},
8488
imageVector = WhatsAppIcons.Call,
8589
tint = MaterialTheme.colorScheme.tertiary,
8690
contentDescription = null

features/chats/src/main/kotlin/io/getstream/whatsappclone/chats/messages/WhatsAppMessagesViewModel.kt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,13 @@ class WhatsAppMessagesViewModel @Inject constructor(
5353
}
5454
}
5555

56-
fun navigateToVideoCall(channelId: String) {
57-
composeNavigator.navigate(WhatsAppScreens.VideoCall.createRoute(channelId))
56+
fun navigateToVideoCall(channelId: String, videoCall: Boolean) {
57+
composeNavigator.navigate(
58+
WhatsAppScreens.VideoCall.createRoute(
59+
callId = channelId,
60+
videoCall = videoCall
61+
)
62+
)
5863
}
5964

6065
private fun fetchChannel(channelId: String) {

features/video/src/main/kotlin/io/getstream/whatsappclone/video/WhatsAppVideoCall.kt

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,25 +18,31 @@ package io.getstream.whatsappclone.video
1818

1919
import androidx.compose.foundation.layout.Box
2020
import androidx.compose.foundation.layout.fillMaxSize
21+
import androidx.compose.foundation.layout.size
2122
import androidx.compose.material.Text
2223
import androidx.compose.material3.MaterialTheme
2324
import androidx.compose.runtime.Composable
2425
import androidx.compose.runtime.LaunchedEffect
2526
import androidx.compose.runtime.getValue
2627
import androidx.compose.ui.Alignment
2728
import androidx.compose.ui.Modifier
29+
import androidx.compose.ui.unit.dp
2830
import androidx.compose.ui.unit.sp
2931
import androidx.hilt.navigation.compose.hiltViewModel
3032
import androidx.lifecycle.compose.collectAsStateWithLifecycle
3133
import io.getstream.video.android.compose.theme.VideoTheme
3234
import io.getstream.video.android.compose.ui.components.call.activecall.CallContent
35+
import io.getstream.video.android.compose.ui.components.call.controls.ControlActions
36+
import io.getstream.video.android.compose.ui.components.call.controls.actions.LeaveCallAction
37+
import io.getstream.video.android.compose.ui.components.call.controls.actions.ToggleMicrophoneAction
3338
import io.getstream.video.android.core.Call
3439
import io.getstream.whatsappclone.designsystem.component.WhatsAppLoadingIndicator
3540
import io.getstream.whatsappclone.uistate.WhatsAppVideoUiState
3641

3742
@Composable
3843
fun WhatsAppVideoCall(
3944
id: String,
45+
videoCall: Boolean,
4046
viewModel: WhatsAppVideoCallViewModel = hiltViewModel()
4147
) {
4248
val uiState by viewModel.videoUiSate.collectAsStateWithLifecycle()
@@ -47,7 +53,11 @@ fun WhatsAppVideoCall(
4753

4854
when (uiState) {
4955
is WhatsAppVideoUiState.Success ->
50-
WhatsAppVideoCallContent(call = (uiState as WhatsAppVideoUiState.Success).data)
56+
WhatsAppVideoCallContent(
57+
call = (uiState as WhatsAppVideoUiState.Success).data,
58+
videoCall = videoCall,
59+
onBackPressed = { viewModel.navigateUp() }
60+
)
5161

5262
is WhatsAppVideoUiState.Error -> WhatsAppVideoCallError()
5363

@@ -57,10 +67,47 @@ fun WhatsAppVideoCall(
5767

5868
@Composable
5969
fun WhatsAppVideoCallContent(
60-
call: Call
70+
call: Call,
71+
videoCall: Boolean,
72+
onBackPressed: () -> Unit
6173
) {
74+
val isMicrophoneEnabled by call.microphone.isEnabled.collectAsStateWithLifecycle()
75+
76+
LaunchedEffect(key1 = call.id) {
77+
if (!videoCall) {
78+
call.camera.setEnabled(false)
79+
}
80+
}
81+
6282
VideoTheme {
63-
CallContent(call = call)
83+
CallContent(
84+
call = call,
85+
onBackPressed = onBackPressed,
86+
controlsContent = {
87+
if (videoCall) {
88+
ControlActions(call = call)
89+
} else {
90+
ControlActions(
91+
call = call,
92+
actions = listOf(
93+
{
94+
ToggleMicrophoneAction(
95+
modifier = Modifier.size(52.dp),
96+
isMicrophoneEnabled = isMicrophoneEnabled,
97+
onCallAction = { call.microphone.setEnabled(it.isEnabled) }
98+
)
99+
},
100+
{
101+
LeaveCallAction(
102+
modifier = Modifier.size(52.dp),
103+
onCallAction = { onBackPressed.invoke() }
104+
)
105+
}
106+
)
107+
)
108+
}
109+
}
110+
)
64111
}
65112
}
66113

features/video/src/main/kotlin/io/getstream/whatsappclone/video/WhatsAppVideoCallViewModel.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,17 @@ import androidx.lifecycle.ViewModel
2121
import androidx.lifecycle.viewModelScope
2222
import dagger.hilt.android.lifecycle.HiltViewModel
2323
import io.getstream.video.android.core.StreamVideo
24+
import io.getstream.whatsappclone.navigation.AppComposeNavigator
2425
import io.getstream.whatsappclone.uistate.WhatsAppVideoUiState
2526
import javax.inject.Inject
2627
import kotlinx.coroutines.flow.MutableStateFlow
2728
import kotlinx.coroutines.flow.StateFlow
2829
import kotlinx.coroutines.launch
2930

3031
@HiltViewModel
31-
class WhatsAppVideoCallViewModel @Inject constructor() : ViewModel() {
32+
class WhatsAppVideoCallViewModel @Inject constructor(
33+
private val composeNavigator: AppComposeNavigator
34+
) : ViewModel() {
3235

3336
private val videoMutableUiState =
3437
MutableStateFlow<WhatsAppVideoUiState>(WhatsAppVideoUiState.Loading)
@@ -61,4 +64,8 @@ class WhatsAppVideoCallViewModel @Inject constructor() : ViewModel() {
6164
}
6265
}
6366
}
67+
68+
fun navigateUp() {
69+
composeNavigator.navigateUp()
70+
}
6471
}

0 commit comments

Comments
 (0)