Show explicit caller choice and already-active radio outcome on Android
This commit is contained in:
1 parent
187fc7fee8
commit
a1f8eaeec2
3 files changed
+38
-9
No files matched your search
@@ -17,7 +17,7 @@ import kotlinx.coroutines.launch
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.ByteOrder
|
||||
|
||||
enum class RadioCallPhase { OUTGOING, INCOMING, RINGING, PREPARING, ENDED }
|
||||
enum class RadioCallPhase { OUTGOING, INCOMING, RINGING, PREPARING, ENDED, WAIT_DECISION }
|
||||
data class RadioCallState(
|
||||
val id: Long, val channelId: String, val peer: Long, val peerName: String, val channelName: String,
|
||||
val incoming: Boolean, val phase: RadioCallPhase, val reason: Int = 0
|
||||
@@ -34,6 +34,7 @@ object RadioCallController {
|
||||
private const val CANCEL = 5
|
||||
private const val FAIL = 6
|
||||
private const val BUSY = 7
|
||||
private const val CONTINUE = 8
|
||||
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
|
||||
private val _state = MutableStateFlow<RadioCallState?>(null)
|
||||
val state: StateFlow<RadioCallState?> = _state
|
||||
@@ -123,7 +124,7 @@ object RadioCallController {
|
||||
if (type == 12) { ready = NativeLib.isReady(); return }
|
||||
if (type == 13) { reset(); return }
|
||||
if (type != 65 || !ready || !NativeLib.isReady()) return
|
||||
if (data == null || data.size != 27 || data[24].toInt() !in 1..4 || data[25].toInt() !in 0..7 || data[26].toInt() !in 0..1) {
|
||||
if (data == null || data.size != 27 || data[24].toInt() !in 1..5 || data[25].toInt() !in 0..9 || data[26].toInt() !in 0..1) {
|
||||
LogManager.addLog("ERROR", "radio", "Invalid call event size=${data?.size}"); return
|
||||
}
|
||||
val buf = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN)
|
||||
@@ -152,7 +153,10 @@ object RadioCallController {
|
||||
return
|
||||
}
|
||||
if (current.phase == RadioCallPhase.ENDED) return
|
||||
if (phase == 3 && !incoming) {
|
||||
if (phase == 5 && !incoming) {
|
||||
CallRingback.stop()
|
||||
_state.value = current.copy(phase = RadioCallPhase.WAIT_DECISION)
|
||||
} else if (phase == 3 && !incoming) {
|
||||
_state.value = current.copy(phase = RadioCallPhase.RINGING)
|
||||
CallRingback.startRinging()
|
||||
} else if (phase == 4) {
|
||||
@@ -177,6 +181,16 @@ object RadioCallController {
|
||||
scope.launch { delay(2500); if (_state.value?.id == st.id && _state.value?.phase == RadioCallPhase.ENDED) clear() }
|
||||
}
|
||||
|
||||
fun continueCall(id: Long) {
|
||||
checkMain()
|
||||
val st = _state.value ?: return
|
||||
if (st.id != id || st.phase != RadioCallPhase.WAIT_DECISION) return
|
||||
_state.value = st.copy(phase = RadioCallPhase.OUTGOING)
|
||||
LogManager.addLog("INFO", "radio", "Caller overrides phone busy id=$id")
|
||||
if (!NativeLib.radioCall(id, CONTINUE)) { finish(st, 5); return }
|
||||
CallRingback.startConnecting()
|
||||
}
|
||||
|
||||
private fun clear() {
|
||||
if (busy()) { IncomingCallManager.stopRinging(); CallRingback.stop() }
|
||||
_state.value = null; _activation.value = null; answerOnVisible = 0
|
||||
@@ -189,6 +203,8 @@ object RadioCallController {
|
||||
4 -> R.string.radio_call_cancelled
|
||||
6 -> R.string.radio_call_no_answer
|
||||
7 -> R.string.radio_call_audio_error
|
||||
8 -> R.string.phone_busy_warning
|
||||
9 -> R.string.radio_call_already_active
|
||||
else -> R.string.radio_call_unavailable
|
||||
}
|
||||
|
||||
|
||||
@@ -72,11 +72,12 @@ private fun fmtDuration(sec: Int): String {
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun callStatusText(phase: CallPhase): String = when (phase) {
|
||||
private fun callStatusText(phase: CallPhase, reason: Int = -1): String = when (phase) {
|
||||
CallPhase.OUTGOING -> stringResource(R.string.call_connecting)
|
||||
CallPhase.RINGING -> stringResource(R.string.call_ringing)
|
||||
CallPhase.WAIT_DECISION -> stringResource(R.string.phone_busy_warning)
|
||||
CallPhase.ACTIVE -> stringResource(R.string.call_talking)
|
||||
CallPhase.ENDED -> stringResource(R.string.call_ended)
|
||||
CallPhase.ENDED -> stringResource(if (reason == 8) R.string.phone_busy_warning else R.string.call_ended)
|
||||
else -> ""
|
||||
}
|
||||
|
||||
@@ -236,7 +237,7 @@ fun CallScreen(
|
||||
Text(name, color = Color.White, fontSize = 24.sp, fontWeight = FontWeight.Medium)
|
||||
Spacer(Modifier.height(8.dp))
|
||||
Text(
|
||||
if (phase == CallPhase.ACTIVE) fmtDuration(duration) else callStatusText(phase),
|
||||
if (phase == CallPhase.ACTIVE) fmtDuration(duration) else callStatusText(phase, st?.reason ?: -1),
|
||||
color = Color(0xFFAEBCC8),
|
||||
fontSize = 16.sp
|
||||
)
|
||||
@@ -273,6 +274,12 @@ fun CallScreen(
|
||||
Text(stringResource(R.string.close))
|
||||
}
|
||||
} else {
|
||||
if (phase == CallPhase.WAIT_DECISION) {
|
||||
Button(onClick = { st?.let { com.utun.chat.data.CallController.continueCall(it.callId) } }) {
|
||||
Text(stringResource(R.string.call_anyway))
|
||||
}
|
||||
Spacer(Modifier.height(20.dp))
|
||||
}
|
||||
if (phase == CallPhase.ACTIVE) {
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(24.dp)) {
|
||||
if (earpieceAvailable) {
|
||||
@@ -331,12 +338,14 @@ fun CallScreen(
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
IconButton(onClick = { viewModel.hangupCall() }) {
|
||||
Icon(Icons.Filled.CallEnd, stringResource(R.string.hang_up), tint = Color.White, modifier = Modifier.size(36.dp))
|
||||
Icon(Icons.Filled.CallEnd, stringResource(if (phase == CallPhase.WAIT_DECISION) R.string.finish_call else R.string.hang_up),
|
||||
tint = Color.White, modifier = Modifier.size(36.dp))
|
||||
}
|
||||
}
|
||||
if (!viewingVideo) {
|
||||
Spacer(Modifier.height(6.dp))
|
||||
Text(stringResource(R.string.hang_up), color = Color(0xFFAEBCC8), fontSize = 12.sp)
|
||||
Text(stringResource(if (phase == CallPhase.WAIT_DECISION) R.string.finish_call else R.string.hang_up),
|
||||
color = Color(0xFFAEBCC8), fontSize = 12.sp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,16 +43,20 @@ fun RadioCallDialog(state: RadioCallState) {
|
||||
RadioCallPhase.INCOMING -> R.string.radio_call_waiting
|
||||
RadioCallPhase.RINGING -> R.string.radio_call_ringing
|
||||
RadioCallPhase.PREPARING -> R.string.radio_call_preparing
|
||||
RadioCallPhase.WAIT_DECISION -> R.string.phone_busy_warning
|
||||
RadioCallPhase.ENDED -> RadioCallController.reasonText(state.reason)
|
||||
}))
|
||||
Spacer(Modifier.height(20.dp))
|
||||
if (state.phase != RadioCallPhase.ENDED && state.phase != RadioCallPhase.PREPARING) {
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||
TextButton(onClick = { RadioCallController.end(state.id) }) {
|
||||
Text(stringResource(if (state.phase == RadioCallPhase.INCOMING) R.string.decline else android.R.string.cancel))
|
||||
Text(stringResource(if (state.phase == RadioCallPhase.INCOMING) R.string.decline
|
||||
else if (state.phase == RadioCallPhase.WAIT_DECISION) R.string.finish_call else android.R.string.cancel))
|
||||
}
|
||||
if (state.phase == RadioCallPhase.INCOMING) {
|
||||
Button(onClick = RadioCallController::accept) { Text(stringResource(R.string.accept)) }
|
||||
} else if (state.phase == RadioCallPhase.WAIT_DECISION) {
|
||||
Button(onClick = { RadioCallController.continueCall(state.id) }) { Text(stringResource(R.string.call_anyway)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user