More work on multiple calls

This commit is contained in:
Juha Heinanen
2026-01-12 22:22:28 +02:00
parent 04656b4449
commit b07f0afbcf
6 changed files with 675 additions and 639 deletions
@@ -830,7 +830,7 @@ class BaresipService: Service() {
return return
} }
"call outgoing" -> { "call outgoing" -> {
if (call!!.status == "transferring") if (call!!.status.value == "transferring")
break break
stopMediaPlayer() stopMediaPlayer()
setCallVolume() setCallVolume()
@@ -989,8 +989,8 @@ class BaresipService: Service() {
} }
"call answered" -> { "call answered" -> {
stopMediaPlayer() stopMediaPlayer()
if (call!!.status == "incoming") if (call!!.status.value == "incoming")
call.status = "answered" call.status.value = "answered"
else else
return return
} }
@@ -1002,7 +1002,7 @@ class BaresipService: Service() {
Log.d(TAG, "AoR $aor call $callp established in mode ${am.mode}") Log.d(TAG, "AoR $aor call $callp established in mode ${am.mode}")
if (am.mode != MODE_IN_COMMUNICATION) if (am.mode != MODE_IN_COMMUNICATION)
am.mode = MODE_IN_COMMUNICATION am.mode = MODE_IN_COMMUNICATION
call!!.status = "connected" call!!.status.value = "connected"
call.onhold = false call.onhold = false
if (ua.account.callHistory) if (ua.account.callHistory)
call.startTime = GregorianCalendar() call.startTime = GregorianCalendar()
@@ -1020,7 +1020,7 @@ class BaresipService: Service() {
else else
playRingBack() playRingBack()
} }
if (!isMainVisible || call.status != "connected") if (!isMainVisible || call.status.value != "connected")
return return
} }
"call verified", "call secure" -> { "call verified", "call secure" -> {
@@ -5,7 +5,9 @@ import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import java.util.* import java.util.*
class Call(val callp: Long, val ua: UserAgent, val peerUri: String, val dir: String, var status: String) { class Call(val callp: Long, val ua: UserAgent, val peerUri: String, val dir: String, initialStatus: String) {
var status: MutableState<String> = mutableStateOf(initialStatus)
var onhold = false var onhold = false
var held = false var held = false
@@ -132,7 +134,7 @@ class Call(val callp: Long, val ua: UserAgent, val peerUri: String, val dir: Str
fun call(status: String): Call? { fun call(status: String): Call? {
for (c in BaresipService.calls.reversed()) for (c in BaresipService.calls.reversed())
if (c.status == status) return c if (c.status.value == status) return c
return null return null
} }
@@ -1,20 +1,20 @@
package com.tutpro.baresip package com.tutpro.baresip
import java.util.* import java.util.GregorianCalendar
class CallRow( data class CallRow(
val aor: String, val peerUri: String, val direction: Int, startTime: GregorianCalendar?, val aor: String,
val stopTime: GregorianCalendar, val recording: Array<String> val peerUri: String,
var direction: Int,
var startTime: GregorianCalendar?,
var stopTime: GregorianCalendar,
var recording: Array<String>
) { ) {
class Details( data class Details(
val direction: Int, val startTime: GregorianCalendar?, var direction: Int,
val stopTime: GregorianCalendar, val recording: Array<String> var startTime: GregorianCalendar?,
var stopTime: GregorianCalendar,
var recording: Array<String>
) )
val details = mutableListOf(Details(direction, startTime, stopTime, recording))
val details = ArrayList<Details>()
init {
details.add(Details(direction, startTime, stopTime, recording))
}
} }
@@ -252,29 +252,20 @@ class MainActivity : ComponentActivity() {
navController = rememberNavController() navController = rememberNavController()
LaunchedEffect(key1 = viewModel, key2 = navController) { LaunchedEffect(key1 = viewModel) {
viewModel.navigationCommand.collect { command -> viewModel.navigationCommand.collect { command ->
Log.d(TAG, "MainActivity: Received NavigationCommand: $command") Log.d(TAG, "MainActivity: Received NavigationCommand: $command")
when (command) { when (command) {
is NavigationCommand.NavigateToChat -> { is NavigationCommand.NavigateToChat -> {
val route = "chat/${command.aor}/${command.peer}" val route = "chat/${command.aor}/${command.peerUri}"
navController.navigate(route) { navController.navigate(route)
launchSingleTop = true
popUpTo("main")
}
} }
is NavigationCommand.NavigateToCalls -> { is NavigationCommand.NavigateToCalls -> {
val route = "calls/${command.aor}" val route = "calls/${command.aor}"
navController.navigate(route) { navController.navigate(route)
launchSingleTop = true
popUpTo("main")
}
} }
is NavigationCommand.NavigateToHome -> { is NavigationCommand.NavigateToHome -> {
navController.navigate("main") { navController.navigate("main")
launchSingleTop = true
popUpTo("main")
}
} }
} }
} }
File diff suppressed because it is too large Load Diff
@@ -4,13 +4,40 @@ import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Mic import androidx.compose.material.icons.filled.Mic
import kotlinx.coroutines.launch
// Sealed class for type-safe navigation events
sealed class NavigationCommand {
object NavigateToHome : NavigationCommand()
data class NavigateToCalls(val aor: String) : NavigationCommand()
data class NavigateToChat(val aor: String, val peerUri: String) : NavigationCommand()
}
class ViewModel: ViewModel() { class ViewModel: ViewModel() {
// A map to store message drafts. Key is "aor:peerUri"
private val messageDrafts = mutableMapOf<String, String>()
fun getAorPeerMessage(aor: String, peerUri: String): String {
return messageDrafts["$aor:$peerUri"] ?: ""
}
fun updateAorPeerMessage(aor: String, peerUri: String, message: String) {
val key = "$aor:$peerUri"
if (message.isEmpty()) {
messageDrafts.remove(key)
} else {
messageDrafts[key] = message
}
}
data class DialerState( data class DialerState(
val callUri: MutableState<String> = mutableStateOf(""), val callUri: MutableState<String> = mutableStateOf(""),
val callUriEnabled: MutableState<Boolean> = mutableStateOf(true), val callUriEnabled: MutableState<Boolean> = mutableStateOf(true),
@@ -43,11 +70,24 @@ class ViewModel: ViewModel() {
private val _hideKeyboard = MutableStateFlow(0) private val _hideKeyboard = MutableStateFlow(0)
val hideKeyboard = _hideKeyboard.asStateFlow() val hideKeyboard = _hideKeyboard.asStateFlow()
private val _navigationCommand = MutableSharedFlow<NavigationCommand>()
val navigationCommand = _navigationCommand.asSharedFlow()
private var _selectedCallRow: CallRow? = null
fun selectCallRow(callRow: CallRow) {
_selectedCallRow = callRow
}
fun consumeSelectedCallRow(): CallRow? {
val callRow = _selectedCallRow
_selectedCallRow = null
return callRow
}
fun onNewMessageReceived(aor: String, peerUri: String) { fun onNewMessageReceived(aor: String, peerUri: String) {
val acc = Account.ofAor(aor) viewModelScope.launch {
if (acc != null) { _navigationCommand.emit(NavigationCommand.NavigateToChat(aor, peerUri))
acc.unreadMessages = true
triggerAccountUpdate()
} }
} }
@@ -60,7 +100,7 @@ class ViewModel: ViewModel() {
} }
fun triggerAccountUpdate() { fun triggerAccountUpdate() {
_accountUpdate.value = _accountUpdate.value + 1 _accountUpdate.value += 1
} }
fun updateMicIcon(icon: ImageVector) { fun updateMicIcon(icon: ImageVector) {
@@ -72,19 +112,23 @@ class ViewModel: ViewModel() {
} }
fun requestShowKeyboard() { fun requestShowKeyboard() {
_showKeyboard.value = _showKeyboard.value + 1 _showKeyboard.value += 1
} }
fun requestHideKeyboard() { fun requestHideKeyboard() {
_hideKeyboard.value = _hideKeyboard.value + 1 _hideKeyboard.value += 1
} }
fun navigateToHome() { fun navigateToHome() {
// This function can be used to navigate to the main screen viewModelScope.launch {
_navigationCommand.emit(NavigationCommand.NavigateToHome)
}
} }
fun navigateToCalls(aor: String) { fun navigateToCalls(aor: String) {
// This function can be used to navigate to the calls screen viewModelScope.launch {
_navigationCommand.emit(NavigationCommand.NavigateToCalls(aor))
}
} }
} }