Files
forkmessager/client-mobile/calls/presentation/CallViewModel.kt
Халимов Рустам 1fb1be47dd Приложение
2026-04-14 01:15:54 +03:00

100 lines
3.3 KiB
Kotlin

package calls.presentation
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import calls.data.remote.WebRtcManager
import chats.data.remote.signalr.ChatEvent
import chats.data.remote.signalr.ChatHubClient
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import org.webrtc.*
import javax.inject.Inject
enum class CallStatus { IDLE, INCOMING, OUTGOING, CONNECTED, ENDED }
data class CallState(
val status: CallStatus = CallStatus.IDLE,
val chatId: String? = null,
val callerName: String = "",
val callerAvatar: String? = null,
val isMuted: Boolean = false,
val isSpeakerOn: Boolean = false,
val localVideoTrack: VideoTrack? = null,
val remoteVideoTrack: VideoTrack? = null
)
@HiltViewModel
class CallViewModel @Inject constructor(
private val webRtcManager: WebRtcManager,
private val signalrClient: ChatHubClient
) : ViewModel() {
private val _state = MutableStateFlow(CallState())
val state: StateFlow<CallState> = _state.asStateFlow()
init {
observeSignaling()
}
private fun observeSignaling() {
signalrClient.events
.onEach { event ->
when (event) {
is ChatEvent.CallIncoming -> onIncomingCall(event)
is ChatEvent.CallAnswered -> onCallAnswered(event)
is ChatEvent.IceCandidateReceived -> onIceCandidate(event)
is ChatEvent.CallEnded -> onCallEnded()
else -> Unit
}
}
.launchIn(viewModelScope)
}
private fun onIncomingCall(event: ChatEvent.CallIncoming) {
_state.update { it.copy(
status = CallStatus.INCOMING,
chatId = event.chatId,
callerName = "User ${event.from}" // TODO: Load actual user info
) }
// Set remote description from offer
webRtcManager.setRemoteDescription(event.offer, SessionDescription.Type.OFFER, object : SdpObserver {
override fun onCreateSuccess(p0: SessionDescription?) {}
override fun onSetSuccess() {}
override fun onCreateFailure(p0: String?) {}
override fun onSetFailure(p0: String?) {}
})
}
private fun onCallAnswered(event: ChatEvent.CallAnswered) {
_state.update { it.copy(status = CallStatus.CONNECTED) }
webRtcManager.setRemoteDescription(event.answer, SessionDescription.Type.ANSWER, object : SdpObserver {
override fun onCreateSuccess(p0: SessionDescription?) {}
override fun onSetSuccess() {}
override fun onCreateFailure(p0: String?) {}
override fun onSetFailure(p0: String?) {}
})
}
private fun onIceCandidate(event: ChatEvent.IceCandidateReceived) {
// Parse candidate JSON and add to peer connection
// webRtcManager.addIceCandidate(...)
}
private fun onCallEnded() {
_state.update { it.copy(status = CallStatus.ENDED) }
webRtcManager.close()
}
fun acceptCall() {
val chatId = _state.value.chatId ?: return
// Create answer and send via SignalR
}
fun endCall() {
val chatId = _state.value.chatId ?: return
// Send call_end via SignalR
onCallEnded()
}
}