refactor: improve separation of concerns in call feature

1. Move UI toggle state out of CallState.Connected:
   - Removed isAudioMuted/isVideoEnabled/isSpeakerOn from domain
     CallState. These are UI concerns, not call state.
   - Added StateFlows for toggles in CallController (isAudioMuted,
     isVideoEnabled, isSpeakerOn) with proper toggle methods.
   - CallScreen reads toggle state from CallController flows.
   - Removed toggleAudioMute/toggleVideo/toggleSpeaker from
     CallManager (no longer manages UI state).

2. Move ICE candidate parsing to quartz layer:
   - Added candidateSdp(), sdpMid(), sdpMLineIndex() parsers and
     serializeCandidate() to CallIceCandidateEvent in quartz.
   - Removed companion object with parseIceCandidate/
     serializeIceCandidate from CallController.
   - CallController now uses quartz-layer parsing directly.
   - Updated IceCandidateSerializationTest accordingly.

3. Add helper methods to CallManager:
   - currentCallId() and currentPeerPubKey() extract from any
     active state, reducing repeated when expressions.

4. Fix empty callId bug in ChatroomScreen:
   - Navigation to ActiveCall now uses callManager.currentCallId()
     instead of hardcoded empty string.

https://claude.ai/code/session_017hZm7yu7CzmcQgZGSaqSXS
This commit is contained in:
Claude
2026-04-02 02:39:41 +00:00
parent f344f00e9d
commit 44d6345e16
7 changed files with 118 additions and 113 deletions
@@ -216,26 +216,23 @@ class CallManager(
}
}
fun toggleAudioMute() {
val current = _state.value
if (current is CallState.Connected) {
_state.value = current.copy(isAudioMuted = !current.isAudioMuted)
fun currentCallId(): String? =
when (val s = _state.value) {
is CallState.Offering -> s.callId
is CallState.IncomingCall -> s.callId
is CallState.Connecting -> s.callId
is CallState.Connected -> s.callId
else -> null
}
}
fun toggleVideo() {
val current = _state.value
if (current is CallState.Connected) {
_state.value = current.copy(isVideoEnabled = !current.isVideoEnabled)
fun currentPeerPubKey(): HexKey? =
when (val s = _state.value) {
is CallState.Offering -> s.peerPubKey
is CallState.IncomingCall -> s.callerPubKey
is CallState.Connecting -> s.peerPubKey
is CallState.Connected -> s.peerPubKey
else -> null
}
}
fun toggleSpeaker() {
val current = _state.value
if (current is CallState.Connected) {
_state.value = current.copy(isSpeakerOn = !current.isSpeakerOn)
}
}
fun reset() {
_state.value = CallState.Idle
@@ -52,9 +52,6 @@ sealed interface CallState {
val peerPubKey: HexKey,
val callType: CallType,
val startedAtEpoch: Long,
val isAudioMuted: Boolean = false,
val isVideoEnabled: Boolean = true,
val isSpeakerOn: Boolean = false,
) : CallState
data class Ended(