Skip to content

Commit 4e88436

Browse files
authored
Merge pull request #108 from GetStream/feature/audio-call
Implement an audio call
2 parents 3805ee9 + 5ffed12 commit 4e88436

File tree

8 files changed

+102
-13
lines changed

8 files changed

+102
-13
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/calls/src/main/kotlin/io/getstream/whatsappclone/calls/info/WhatsAppCallHistoryInfoBody.kt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package io.getstream.whatsappclone.calls.info
1818

19+
import androidx.compose.foundation.clickable
1920
import androidx.compose.foundation.layout.padding
2021
import androidx.compose.foundation.layout.size
2122
import androidx.compose.foundation.shape.CircleShape
@@ -28,6 +29,7 @@ import androidx.compose.ui.Modifier
2829
import androidx.compose.ui.draw.clip
2930
import androidx.compose.ui.unit.dp
3031
import androidx.constraintlayout.compose.ConstraintLayout
32+
import androidx.hilt.navigation.compose.hiltViewModel
3133
import com.skydoves.landscapist.glide.GlideImage
3234
import io.getstream.whatsappclone.designsystem.R
3335
import io.getstream.whatsappclone.designsystem.icon.WhatsAppIcons
@@ -40,8 +42,8 @@ import java.util.Date
4042
@Composable
4143
fun WhatsAppCallHistoryInfoBody(
4244
modifier: Modifier,
43-
whatsAppUser: WhatsAppUser
44-
45+
whatsAppUser: WhatsAppUser,
46+
whatsAppCallHistoryViewModel: WhatsAppCallHistoryViewModel = hiltViewModel()
4547
) {
4648
ConstraintLayout(modifier = modifier.padding(12.dp)) {
4749
val (image, name, call, divider, location, date) = createRefs()
@@ -77,6 +79,12 @@ fun WhatsAppCallHistoryInfoBody(
7779
.constrainAs(call) {
7880
top.linkTo(parent.top)
7981
end.linkTo(parent.end)
82+
}
83+
.clickable {
84+
whatsAppCallHistoryViewModel.navigateToVideoCall(
85+
channelId = whatsAppUser.cell,
86+
videoCall = false
87+
)
8088
},
8189
imageVector = WhatsAppIcons.Call,
8290
tint = GREEN450,

features/calls/src/main/kotlin/io/getstream/whatsappclone/calls/info/WhatsAppCallHistoryViewModel.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package io.getstream.whatsappclone.calls.info
1919
import androidx.lifecycle.ViewModel
2020
import dagger.hilt.android.lifecycle.HiltViewModel
2121
import io.getstream.whatsappclone.navigation.AppComposeNavigator
22+
import io.getstream.whatsappclone.navigation.WhatsAppScreens
2223
import javax.inject.Inject
2324

2425
@HiltViewModel
@@ -29,4 +30,13 @@ class WhatsAppCallHistoryViewModel @Inject constructor(
2930
fun navigateUp() {
3031
composeNavigator.navigateUp()
3132
}
33+
34+
fun navigateToVideoCall(channelId: String, videoCall: Boolean) {
35+
composeNavigator.navigate(
36+
WhatsAppScreens.VideoCall.createRoute(
37+
callId = channelId,
38+
videoCall = videoCall
39+
)
40+
)
41+
}
3242
}

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)