Started work on multiple calls
This commit is contained in:
@@ -1,5 +1,8 @@
|
|||||||
package com.tutpro.baresip
|
package com.tutpro.baresip
|
||||||
|
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
|
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, var status: String) {
|
||||||
@@ -15,6 +18,27 @@ class Call(val callp: Long, val ua: UserAgent, val peerUri: String, val dir: Str
|
|||||||
var referTo = ""
|
var referTo = ""
|
||||||
var dumpfiles = arrayOf("", "")
|
var dumpfiles = arrayOf("", "")
|
||||||
|
|
||||||
|
// UI state properties
|
||||||
|
val callUri: MutableState<String> = mutableStateOf("")
|
||||||
|
val callUriEnabled: MutableState<Boolean> = mutableStateOf(true)
|
||||||
|
val callUriLabel: MutableState<String> = mutableStateOf("")
|
||||||
|
val securityIconTint: MutableState<Int> = mutableIntStateOf(-1)
|
||||||
|
val showCallTimer: MutableState<Boolean> = mutableStateOf(false)
|
||||||
|
var callDuration: Int = 0
|
||||||
|
val showSuggestions: MutableState<Boolean> = mutableStateOf(false)
|
||||||
|
val showCallButton: MutableState<Boolean> = mutableStateOf(true)
|
||||||
|
val callButtonEnabled: MutableState<Boolean> = mutableStateOf(true)
|
||||||
|
val showCancelButton: MutableState<Boolean> = mutableStateOf(false)
|
||||||
|
val showAnswerRejectButtons: MutableState<Boolean> = mutableStateOf(false)
|
||||||
|
val showHangupButton: MutableState<Boolean> = mutableStateOf(false)
|
||||||
|
val showOnHoldNotice: MutableState<Boolean> = mutableStateOf(false)
|
||||||
|
val callOnHold: MutableState<Boolean> = mutableStateOf(false)
|
||||||
|
val transferButtonEnabled: MutableState<Boolean> = mutableStateOf(false)
|
||||||
|
val callTransfer: MutableState<Boolean> = mutableStateOf(false)
|
||||||
|
val dtmfText: MutableState<String> = mutableStateOf("")
|
||||||
|
val dtmfEnabled: MutableState<Boolean> = mutableStateOf(false)
|
||||||
|
val focusDtmf: MutableState<Boolean> = mutableStateOf(false)
|
||||||
|
|
||||||
fun add() {
|
fun add() {
|
||||||
BaresipService.calls.add(0, this)
|
BaresipService.calls.add(0, this)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -841,26 +841,6 @@ private fun BottomBar(ctx: Context, viewModel: ViewModel, navController: NavCont
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val callUri = mutableStateOf("")
|
|
||||||
private var callUriEnabled = mutableStateOf(true)
|
|
||||||
private val callUriLabel = mutableStateOf("")
|
|
||||||
private var securityIconTint = mutableIntStateOf(-1)
|
|
||||||
private val showCallTimer = mutableStateOf(false)
|
|
||||||
private var callDuration = 0
|
|
||||||
private val showSuggestions = mutableStateOf(false)
|
|
||||||
private val showCallButton = mutableStateOf(true)
|
|
||||||
private val callButtonEnabled = mutableStateOf(true)
|
|
||||||
private val showCancelButton = mutableStateOf(false)
|
|
||||||
private val showAnswerRejectButtons = mutableStateOf(false)
|
|
||||||
private val showHangupButton = mutableStateOf(false)
|
|
||||||
private val showOnHoldNotice = mutableStateOf(false)
|
|
||||||
private var callOnHold = mutableStateOf(false)
|
|
||||||
private val transferButtonEnabled = mutableStateOf(false)
|
|
||||||
private val callTransfer = mutableStateOf(false)
|
|
||||||
private var dtmfText = mutableStateOf("")
|
|
||||||
private val dtmfEnabled = mutableStateOf(false)
|
|
||||||
private val focusDtmf = mutableStateOf(false)
|
|
||||||
|
|
||||||
private val alertTitle = mutableStateOf("")
|
private val alertTitle = mutableStateOf("")
|
||||||
private val alertMessage = mutableStateOf("")
|
private val alertMessage = mutableStateOf("")
|
||||||
private val showAlert = mutableStateOf(false)
|
private val showAlert = mutableStateOf(false)
|
||||||
@@ -2116,24 +2096,12 @@ private fun showCall(ctx: Context, viewModel: ViewModel, ua: UserAgent?, showCal
|
|||||||
val call = showCall ?: ua.currentCall()
|
val call = showCall ?: ua.currentCall()
|
||||||
if (call == null) {
|
if (call == null) {
|
||||||
pullToRefreshEnabled.value = true
|
pullToRefreshEnabled.value = true
|
||||||
if (ua.account.resumeUri != "")
|
viewModel.dialerState.callUri.value = ua.account.resumeUri
|
||||||
callUri.value = ua.account.resumeUri
|
viewModel.dialerState.callUriLabel.value = ctx.getString(R.string.outgoing_call_to_dots)
|
||||||
else
|
viewModel.dialerState.callUriEnabled.value = true
|
||||||
callUri.value = ""
|
viewModel.dialerState.showCallButton.value = true
|
||||||
callUriLabel.value = ctx.getString(R.string.outgoing_call_to_dots)
|
viewModel.dialerState.callButtonEnabled.value = true
|
||||||
callUriEnabled.value = true
|
viewModel.dialerState.showSuggestions.value = false
|
||||||
showCallTimer.value = false
|
|
||||||
securityIconTint.intValue = -1
|
|
||||||
showHangupButton.value = false
|
|
||||||
callTransfer.value = false
|
|
||||||
dtmfText.value = ""
|
|
||||||
dtmfEnabled.value = false
|
|
||||||
focusDtmf.value = false
|
|
||||||
showCallButton.value = true
|
|
||||||
callButtonEnabled.value = true
|
|
||||||
showCancelButton.value = false
|
|
||||||
showAnswerRejectButtons.value = false
|
|
||||||
showOnHoldNotice.value = false
|
|
||||||
dialpadButtonEnabled.value = true
|
dialpadButtonEnabled.value = true
|
||||||
if (BaresipService.isMicMuted) {
|
if (BaresipService.isMicMuted) {
|
||||||
BaresipService.isMicMuted = false
|
BaresipService.isMicMuted = false
|
||||||
@@ -2141,84 +2109,84 @@ private fun showCall(ctx: Context, viewModel: ViewModel, ua: UserAgent?, showCal
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pullToRefreshEnabled.value = false
|
pullToRefreshEnabled.value = false
|
||||||
callUriEnabled.value = false
|
call.callUriEnabled.value = false
|
||||||
val isLandscape = ctx.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
|
val isLandscape = ctx.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
|
||||||
if (isLandscape || call.held || call.status != "connected") {
|
if (isLandscape || call.held || call.status != "connected") {
|
||||||
focusDtmf.value = false
|
call.focusDtmf.value = false
|
||||||
dtmfEnabled.value = !call.held
|
call.dtmfEnabled.value = !call.held
|
||||||
Handler(Looper.getMainLooper()).postDelayed({
|
Handler(Looper.getMainLooper()).postDelayed({
|
||||||
viewModel.requestHideKeyboard()
|
viewModel.requestHideKeyboard()
|
||||||
}, 25)
|
}, 25)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
dtmfEnabled.value = true
|
call.dtmfEnabled.value = true
|
||||||
focusDtmf.value = true
|
call.focusDtmf.value = true
|
||||||
viewModel.requestShowKeyboard()
|
viewModel.requestShowKeyboard()
|
||||||
}
|
}
|
||||||
when (call.status) {
|
when (call.status) {
|
||||||
"outgoing", "transferring", "answered" -> {
|
"outgoing", "transferring", "answered" -> {
|
||||||
callUriLabel.value = if (call.status == "answered")
|
call.callUriLabel.value = if (call.status == "answered")
|
||||||
ctx.getString(R.string.incoming_call_from_dots)
|
ctx.getString(R.string.incoming_call_from_dots)
|
||||||
else
|
else
|
||||||
ctx.getString(R.string.outgoing_call_to_dots)
|
ctx.getString(R.string.outgoing_call_to_dots)
|
||||||
callUri.value = Utils.friendlyUri(ctx, call.peerUri, ua.account)
|
call.callUri.value = Utils.friendlyUri(ctx, call.peerUri, ua.account)
|
||||||
showCallTimer.value = false
|
call.showCallTimer.value = false
|
||||||
securityIconTint.intValue = -1
|
call.securityIconTint.value = -1
|
||||||
showCallButton.value = false
|
call.showCallButton.value = false
|
||||||
showCancelButton.value = call.status == "outgoing"
|
call.showCancelButton.value = call.status == "outgoing"
|
||||||
showHangupButton.value = !showCancelButton.value
|
call.showHangupButton.value = !call.showCancelButton.value
|
||||||
showAnswerRejectButtons.value = false
|
call.showAnswerRejectButtons.value = false
|
||||||
showOnHoldNotice.value = false
|
call.showOnHoldNotice.value = false
|
||||||
dialpadButtonEnabled.value = false
|
dialpadButtonEnabled.value = false
|
||||||
}
|
}
|
||||||
"incoming" -> {
|
"incoming" -> {
|
||||||
showCallTimer.value = false
|
call.showCallTimer.value = false
|
||||||
securityIconTint.intValue = -1
|
call.securityIconTint.value = -1
|
||||||
val uri = call.diverterUri()
|
val uri = call.diverterUri()
|
||||||
if (uri != "") {
|
if (uri != "") {
|
||||||
callUriLabel.value = ctx.getString(R.string.diverted_by_dots)
|
call.callUriLabel.value = ctx.getString(R.string.diverted_by_dots)
|
||||||
callUri.value = Utils.friendlyUri(ctx, uri, ua.account)
|
call.callUri.value = Utils.friendlyUri(ctx, uri, ua.account)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
callUriLabel.value = ctx.getString(R.string.incoming_call_from_dots)
|
call.callUriLabel.value = ctx.getString(R.string.incoming_call_from_dots)
|
||||||
callUri.value = Utils.friendlyUri(ctx, call.peerUri, ua.account)
|
call.callUri.value = Utils.friendlyUri(ctx, call.peerUri, ua.account)
|
||||||
}
|
}
|
||||||
showCallButton.value = false
|
call.showCallButton.value = false
|
||||||
showCancelButton.value = false
|
call.showCancelButton.value = false
|
||||||
showHangupButton.value = false
|
call.showHangupButton.value = false
|
||||||
showAnswerRejectButtons.value = true
|
call.showAnswerRejectButtons.value = true
|
||||||
showOnHoldNotice.value = false
|
call.showOnHoldNotice.value = false
|
||||||
dialpadButtonEnabled.value = false
|
dialpadButtonEnabled.value = false
|
||||||
}
|
}
|
||||||
"connected" -> {
|
"connected" -> {
|
||||||
if (call.referTo != "") {
|
if (call.referTo != "") {
|
||||||
callUriLabel.value = ctx.getString(R.string.outgoing_call_to_dots)
|
call.callUriLabel.value = ctx.getString(R.string.outgoing_call_to_dots)
|
||||||
callUri.value = Utils.friendlyUri(ctx, call.referTo, ua.account)
|
call.callUri.value = Utils.friendlyUri(ctx, call.referTo, ua.account)
|
||||||
transferButtonEnabled.value = false
|
call.transferButtonEnabled.value = false
|
||||||
} else {
|
} else {
|
||||||
if (call.dir == "out") {
|
if (call.dir == "out") {
|
||||||
callUriLabel.value = ctx.getString(R.string.outgoing_call_to_dots)
|
call.callUriLabel.value = ctx.getString(R.string.outgoing_call_to_dots)
|
||||||
callUri.value = Utils.friendlyUri(ctx, call.peerUri, ua.account)
|
call.callUri.value = Utils.friendlyUri(ctx, call.peerUri, ua.account)
|
||||||
} else {
|
} else {
|
||||||
callUriLabel.value = ctx.getString(R.string.incoming_call_from_dots)
|
call.callUriLabel.value = ctx.getString(R.string.incoming_call_from_dots)
|
||||||
callUri.value = Utils.friendlyUri(ctx, call.peerUri, ua.account)
|
call.callUri.value = Utils.friendlyUri(ctx, call.peerUri, ua.account)
|
||||||
}
|
}
|
||||||
transferButtonEnabled.value = true
|
call.transferButtonEnabled.value = true
|
||||||
}
|
}
|
||||||
callTransfer.value = call.onHoldCall != null
|
call.callTransfer.value = call.onHoldCall != null
|
||||||
callDuration = call.duration()
|
call.callDuration = call.duration()
|
||||||
showCallTimer.value = true
|
call.showCallTimer.value = true
|
||||||
if (ua.account.mediaEnc == "")
|
if (ua.account.mediaEnc == "")
|
||||||
securityIconTint.intValue = -1
|
call.securityIconTint.value = -1
|
||||||
else
|
else
|
||||||
securityIconTint.intValue = call.security
|
call.securityIconTint.value = call.security
|
||||||
showCallButton.value = false
|
call.showCallButton.value = false
|
||||||
showCancelButton.value = false
|
call.showCancelButton.value = false
|
||||||
showHangupButton.value = true
|
call.showHangupButton.value = true
|
||||||
showAnswerRejectButtons.value = false
|
call.showAnswerRejectButtons.value = false
|
||||||
callOnHold.value = call.onhold
|
call.callOnHold.value = call.onhold
|
||||||
Handler(Looper.getMainLooper()).postDelayed({
|
Handler(Looper.getMainLooper()).postDelayed({
|
||||||
showOnHoldNotice.value = call.held
|
call.showOnHoldNotice.value = call.held
|
||||||
}, 100)
|
}, 100)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,118 +1,90 @@
|
|||||||
package com.tutpro.baresip
|
package com.tutpro.baresip
|
||||||
|
|
||||||
import android.app.Application
|
import androidx.compose.runtime.MutableState
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
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 androidx.compose.runtime.State
|
|
||||||
import androidx.compose.runtime.mutableIntStateOf
|
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
|
||||||
import androidx.lifecycle.AndroidViewModel
|
|
||||||
import androidx.lifecycle.viewModelScope
|
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
|
||||||
import kotlinx.coroutines.flow.asSharedFlow
|
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
sealed class NavigationCommand {
|
class ViewModel: ViewModel() {
|
||||||
data class NavigateToChat(val aor: String, val peer: String?) : NavigationCommand()
|
|
||||||
data class NavigateToCalls(val aor: String) : NavigationCommand()
|
|
||||||
object NavigateToHome: NavigationCommand()
|
|
||||||
// Add other navigation commands as needed
|
|
||||||
}
|
|
||||||
|
|
||||||
data class AorPeer(val aor: String, val peer: String)
|
data class DialerState(
|
||||||
|
val callUri: MutableState<String> = mutableStateOf(""),
|
||||||
|
val callUriEnabled: MutableState<Boolean> = mutableStateOf(true),
|
||||||
|
val callUriLabel: MutableState<String> = mutableStateOf(""),
|
||||||
|
val showSuggestions: MutableState<Boolean> = mutableStateOf(false),
|
||||||
|
val showCallButton: MutableState<Boolean> = mutableStateOf(true),
|
||||||
|
val callButtonEnabled: MutableState<Boolean> = mutableStateOf(true),
|
||||||
|
)
|
||||||
|
|
||||||
class ViewModel(application: Application) : AndroidViewModel(application) {
|
val dialerState = DialerState()
|
||||||
|
|
||||||
|
private val _calls = MutableStateFlow<List<Call>>(emptyList())
|
||||||
|
val calls = _calls.asStateFlow()
|
||||||
|
|
||||||
private val _selectedAor = MutableStateFlow("")
|
private val _selectedAor = MutableStateFlow("")
|
||||||
val selectedAor: StateFlow<String> = _selectedAor.asStateFlow()
|
val selectedAor = _selectedAor.asStateFlow()
|
||||||
|
|
||||||
fun updateSelectedAor(newValue: String) {
|
|
||||||
_selectedAor.value = newValue
|
|
||||||
}
|
|
||||||
|
|
||||||
private val _accountUpdate = MutableStateFlow(0)
|
private val _accountUpdate = MutableStateFlow(0)
|
||||||
val accountUpdate: StateFlow<Int> = _accountUpdate
|
val accountUpdate = _accountUpdate.asStateFlow()
|
||||||
|
|
||||||
fun triggerAccountUpdate() {
|
|
||||||
_accountUpdate.value++
|
|
||||||
}
|
|
||||||
|
|
||||||
private val _aorPeerMessage = MutableStateFlow(mutableMapOf<AorPeer, String>())
|
|
||||||
|
|
||||||
fun updateAorPeerMessage(aor: String, peerUri: String, message: String) {
|
|
||||||
val key = AorPeer(aor, peerUri)
|
|
||||||
if (message == "")
|
|
||||||
_aorPeerMessage.value.remove(key)
|
|
||||||
else
|
|
||||||
_aorPeerMessage.value[key] = message
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getAorPeerMessage(aor: String, peerUri: String): String {
|
|
||||||
val key = AorPeer(aor, peerUri)
|
|
||||||
return _aorPeerMessage.value.getOrDefault(key, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
private val _showKeyboard = mutableIntStateOf(0)
|
|
||||||
val showKeyboard: State<Int> = _showKeyboard
|
|
||||||
|
|
||||||
fun requestShowKeyboard() {
|
|
||||||
_showKeyboard.intValue++
|
|
||||||
}
|
|
||||||
|
|
||||||
private val _hideKeyboard = mutableIntStateOf(0)
|
|
||||||
val hideKeyboard: State<Int> = _hideKeyboard
|
|
||||||
|
|
||||||
fun requestHideKeyboard() {
|
|
||||||
_hideKeyboard.intValue++
|
|
||||||
}
|
|
||||||
|
|
||||||
private val _micIcon = MutableStateFlow(Icons.Filled.Mic)
|
private val _micIcon = MutableStateFlow(Icons.Filled.Mic)
|
||||||
val micIcon: StateFlow<ImageVector> = _micIcon.asStateFlow()
|
val micIcon = _micIcon.asStateFlow()
|
||||||
|
|
||||||
|
private val _isDialpadVisible = MutableStateFlow(false)
|
||||||
|
val isDialpadVisible = _isDialpadVisible.asStateFlow()
|
||||||
|
|
||||||
|
private val _showKeyboard = MutableStateFlow(0)
|
||||||
|
val showKeyboard = _showKeyboard.asStateFlow()
|
||||||
|
|
||||||
|
private val _hideKeyboard = MutableStateFlow(0)
|
||||||
|
val hideKeyboard = _hideKeyboard.asStateFlow()
|
||||||
|
|
||||||
|
fun onNewMessageReceived(aor: String, peerUri: String) {
|
||||||
|
val acc = Account.ofAor(aor)
|
||||||
|
if (acc != null) {
|
||||||
|
acc.unreadMessages = true
|
||||||
|
triggerAccountUpdate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateCalls(calls: List<Call>) {
|
||||||
|
_calls.value = calls
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateSelectedAor(aor: String) {
|
||||||
|
_selectedAor.value = aor
|
||||||
|
}
|
||||||
|
|
||||||
|
fun triggerAccountUpdate() {
|
||||||
|
_accountUpdate.value = _accountUpdate.value + 1
|
||||||
|
}
|
||||||
|
|
||||||
fun updateMicIcon(icon: ImageVector) {
|
fun updateMicIcon(icon: ImageVector) {
|
||||||
_micIcon.value = icon
|
_micIcon.value = icon
|
||||||
}
|
}
|
||||||
|
|
||||||
private val _isDialpadVisible = MutableStateFlow(false)
|
|
||||||
val isDialpadVisible: StateFlow<Boolean> = _isDialpadVisible
|
|
||||||
|
|
||||||
fun toggleDialpadVisibility() {
|
fun toggleDialpadVisibility() {
|
||||||
_isDialpadVisible.value = !_isDialpadVisible.value
|
_isDialpadVisible.value = !_isDialpadVisible.value
|
||||||
}
|
}
|
||||||
|
|
||||||
private val _selectedCallRow = MutableStateFlow<CallRow?>(null)
|
fun requestShowKeyboard() {
|
||||||
|
_showKeyboard.value = _showKeyboard.value + 1
|
||||||
fun selectCallRow(callRow: CallRow) {
|
|
||||||
_selectedCallRow.value = callRow
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun consumeSelectedCallRow(): CallRow? {
|
fun requestHideKeyboard() {
|
||||||
val callRow = _selectedCallRow.value
|
_hideKeyboard.value = _hideKeyboard.value + 1
|
||||||
_selectedCallRow.value = null
|
|
||||||
return callRow
|
|
||||||
}
|
|
||||||
|
|
||||||
private val _navigationCommand = MutableSharedFlow<NavigationCommand>()
|
|
||||||
val navigationCommand = _navigationCommand.asSharedFlow()
|
|
||||||
|
|
||||||
fun onNewMessageReceived(aor: String, peer: String) {
|
|
||||||
viewModelScope.launch {
|
|
||||||
_navigationCommand.emit(NavigationCommand.NavigateToChat(aor, peer))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun navigateToCalls(aor: String) {
|
|
||||||
viewModelScope.launch {
|
|
||||||
_navigationCommand.emit(NavigationCommand.NavigateToCalls(aor))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun navigateToHome() {
|
fun navigateToHome() {
|
||||||
viewModelScope.launch {
|
// This function can be used to navigate to the main screen
|
||||||
_navigationCommand.emit(NavigationCommand.NavigateToHome)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun navigateToCalls(aor: String) {
|
||||||
|
// This function can be used to navigate to the calls screen
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user