Send isFinalized with rtt text

This commit is contained in:
Pavel Prystinka 2024-11-20 12:43:58 -08:00
Родитель fa994e00dd
Коммит 36dc8fa3f4
15 изменённых файлов: 64 добавлений и 47 удалений

Просмотреть файл

@ -96,6 +96,7 @@ internal class DependencyInjectionContainerImpl(
callingService,
appStore,
avatarViewManager,
configuration.localUserIdentifier,
)
}

Просмотреть файл

@ -10,6 +10,7 @@ internal data class RttMessage(
val senderUserRawId: String,
val senderName: String,
val localCreatedTime: Date,
val isLocal: Boolean,
) {
val isFinalized = message.endsWith("\n")
}

Просмотреть файл

@ -93,9 +93,6 @@ internal class CallCompositeActivityViewModel(
?: CallCompositeAudioVideoMode.AUDIO_AND_VIDEO,
callType = container.configuration.callConfig.callType,
capabilitiesManager = container.capabilitiesManager,
captionsDataManager = container.captionsDataManager,
localUserIdentifier = container.configuration.localUserIdentifier,
avatarViewManager = container.avatarViewManager,
)
}
}

Просмотреть файл

@ -3,7 +3,6 @@
package com.azure.android.communication.ui.calling.presentation.fragment.calling
import com.azure.android.communication.common.CommunicationIdentifier
import com.azure.android.communication.ui.calling.configuration.CallType
import com.azure.android.communication.ui.calling.models.CallCompositeAudioVideoMode
import com.azure.android.communication.ui.calling.models.CallCompositeCallScreenOptions
@ -13,9 +12,7 @@ import com.azure.android.communication.ui.calling.models.ParticipantInfoModel
import com.azure.android.communication.ui.calling.models.ParticipantStatus
import com.azure.android.communication.ui.calling.presentation.fragment.BaseViewModel
import com.azure.android.communication.ui.calling.presentation.fragment.factories.CallingViewModelFactory
import com.azure.android.communication.ui.calling.presentation.manager.AvatarViewManager
import com.azure.android.communication.ui.calling.presentation.manager.CapabilitiesManager
import com.azure.android.communication.ui.calling.presentation.manager.CaptionsDataManager
import com.azure.android.communication.ui.calling.presentation.manager.NetworkManager
import com.azure.android.communication.ui.calling.redux.Store
import com.azure.android.communication.ui.calling.redux.action.CallingAction
@ -41,9 +38,6 @@ internal class CallingViewModel(
val avMode: CallCompositeAudioVideoMode,
private val callType: CallType? = null,
private val capabilitiesManager: CapabilitiesManager,
private val captionsDataManager: CaptionsDataManager,
private val localUserIdentifier: CommunicationIdentifier?,
private val avatarViewManager: AvatarViewManager,
) :
BaseViewModel(store) {

Просмотреть файл

@ -20,4 +20,5 @@ internal data class CaptionsRttRecord(
val isFinal: Boolean,
val timestamp: Date,
val type: CaptionsRttType,
val isLocal: Boolean? = null,
)

Просмотреть файл

@ -19,6 +19,7 @@ import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.view.isVisible
import androidx.core.view.marginTop
import androidx.core.widget.addTextChangedListener
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
@ -48,7 +49,6 @@ internal class CaptionsView : FrameLayout {
private lateinit var captionsStartProgressLayout: LinearLayout
private lateinit var recyclerViewAdapter: CaptionsRecyclerViewAdapter
// private val captionsData = mutableListOf<CaptionsRttEntryModel>()
private var isAtBottom = true
private var isMaximized = false
@ -85,31 +85,15 @@ internal class CaptionsView : FrameLayout {
resizeButton.setOnClickListener { this.onResizeButtonClicked() }
}
rttInputText.addTextChangedListener {
onEditTextChanged()
}
rttInputText.setOnEditorActionListener { view, actionId, _ ->
onEditTextAction(view, actionId)
}
}
private fun onEditTextAction(view: TextView, actionId: Int): Boolean {
if (actionId == EditorInfo.IME_ACTION_SEND) {
// Handle the "Send" action
val message = view.text.toString()
if (message.isNotBlank()) {
viewModel.sendRttMessage(message)
view.text = ""
view.requestFocus()
// Ensure the keyboard remains visible
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT)
}
return true
}
return false
}
@SuppressLint("NotifyDataSetChanged")
fun start(
viewLifecycleOwner: LifecycleOwner,
@ -175,9 +159,38 @@ internal class CaptionsView : FrameLayout {
)
}
private fun onEditTextChanged() {
val message = rttInputText.text.toString()
if (message.isNotBlank()) {
viewModel.sendRttMessage(message, false)
}
}
private fun onEditTextAction(view: TextView, actionId: Int): Boolean {
if (actionId == EditorInfo.IME_ACTION_SEND) {
val message = view.text.toString()
viewModel.sendRttMessage(message, true)
if (message.isNotBlank()) {
view.text = ""
view.requestFocus()
// Ensure the keyboard remains visible
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT)
}
return true
}
return false
}
private fun onItemUpdated(index: Int) {
if (index >= 0) {
val shouldScrollToBottom = isAtBottom
val updatedItem = viewModel.captionsAndRttData[index]
if (updatedItem.type == CaptionsRttType.RTT && updatedItem.isLocal == true && updatedItem.isFinal) {
rttInputText.text.clear()
}
recyclerViewAdapter.notifyItemChanged(index)
requestAccessibilityFocus(index)
if (shouldScrollToBottom) {

Просмотреть файл

@ -65,7 +65,7 @@ internal class CaptionsViewModel(
captionsState: CaptionsState
) = captionsState.status == CaptionsStatus.START_REQUESTED
fun sendRttMessage(message: String) {
dispatch(RttAction.SendRtt(message))
fun sendRttMessage(message: String, isFinal: Boolean) {
dispatch(RttAction.SendRtt(message, isFinal))
}
}

Просмотреть файл

@ -4,6 +4,7 @@
package com.azure.android.communication.ui.calling.presentation.manager
import android.graphics.Bitmap
import com.azure.android.communication.common.CommunicationIdentifier
import com.azure.android.communication.ui.calling.models.CallCompositeCaptionsData
import com.azure.android.communication.ui.calling.models.CaptionsResultType
import com.azure.android.communication.ui.calling.presentation.fragment.calling.CallingFragment
@ -26,6 +27,7 @@ internal class CaptionsDataManager(
private val callingService: CallingService,
private val appStore: AppStore<ReduxState>,
private val avatarViewManager: AvatarViewManager,
private val localParticipantIdentifier: CommunicationIdentifier?,
) {
private val mutex = Mutex()
private val captionsAndRttMutableList = mutableListOf<CaptionsRttRecord>()
@ -54,7 +56,7 @@ internal class CaptionsDataManager(
languageCode = languageCode,
isFinal = captionData.resultType == CaptionsResultType.FINAL,
timestamp = captionData.timestamp,
type = CaptionsRttType.CAPTIONS
type = CaptionsRttType.CAPTIONS,
)
removeOverflownCaptionsFromCache()
@ -75,7 +77,8 @@ internal class CaptionsDataManager(
languageCode = null,
isFinal = rttRecord.isFinalized,
timestamp = rttRecord.localCreatedTime,
type = CaptionsRttType.RTT
type = CaptionsRttType.RTT,
isLocal = rttRecord.isLocal,
)
removeOverflownCaptionsFromCache()
@ -163,6 +166,14 @@ internal class CaptionsDataManager(
private fun getParticipantCustomizationsBitmap(speakerRawId: String): Pair<String?, Bitmap?> {
val remoteParticipantViewData = avatarViewManager.getRemoteParticipantViewData(speakerRawId)
return Pair(remoteParticipantViewData?.displayName, remoteParticipantViewData?.avatarBitmap)
if (remoteParticipantViewData!= null) {
return Pair(remoteParticipantViewData.displayName, remoteParticipantViewData.avatarBitmap)
}
val localParticipantViewData = avatarViewManager.callCompositeLocalOptions?.participantViewData
if (localParticipantViewData != null && localParticipantIdentifier?.rawId == speakerRawId) {
return Pair(localParticipantViewData.displayName, localParticipantViewData.avatarBitmap)
}
return Pair(null, null)
}
}

Просмотреть файл

@ -5,7 +5,7 @@ package com.azure.android.communication.ui.calling.redux.action
internal sealed class RttAction : Action {
class RttMessagesUpdated(val rttContent: String, val participantId: String) : RttAction()
class SendRtt(val message: String) : RttAction()
class SendRtt(val message: String, val isFinalized: Boolean) : RttAction()
class DisableRttLocally() : RttAction()

Просмотреть файл

@ -147,7 +147,7 @@ internal class CallingMiddlewareImpl(
callingMiddlewareActionHandler.setCaptionsCaptionLanguage(action.language, store)
}
is RttAction.SendRtt -> {
callingMiddlewareActionHandler.sendRttMessage(action.message, store)
callingMiddlewareActionHandler.sendRttMessage(action.message, action.isFinalized, store)
}
}
next(action)

Просмотреть файл

@ -107,7 +107,7 @@ internal interface CallingMiddlewareActionHandler {
fun stopCaptions(store: Store<ReduxState>)
fun setCaptionsSpokenLanguage(language: String, store: Store<ReduxState>)
fun setCaptionsCaptionLanguage(language: String, store: Store<ReduxState>)
fun sendRttMessage(message: String, store: Store<ReduxState>)
fun sendRttMessage(message: String, isFinalized: Boolean, store: Store<ReduxState>)
}
internal class CallingMiddlewareActionHandlerImpl(
@ -938,11 +938,11 @@ internal class CallingMiddlewareActionHandlerImpl(
}
}
override fun sendRttMessage(message: String, store: Store<ReduxState>) {
override fun sendRttMessage(message: String, isFinalized: Boolean, store: Store<ReduxState>) {
if (!store.getCurrentState().rttState.isRttActive) {
store.dispatch(RttAction.EnableRtt())
}
callingService.sendRttMessage(message)
callingService.sendRttMessage(message, isFinalized)
}
private fun subscribeRttStateUpdate(store: Store<ReduxState>) {
@ -951,7 +951,6 @@ internal class CallingMiddlewareActionHandlerImpl(
if (!store.getCurrentState().rttState.isRttActive) {
store.dispatch(RttAction.EnableRtt())
}
// store.dispatch(RttAction.RttMessagesUpdated(it.first, it.second))
}
}
}

Просмотреть файл

@ -194,8 +194,8 @@ internal class CallingService(
return callingSdk.startCall(cameraState, audioState)
}
fun sendRttMessage(message: String) {
callingSdk.sendRttMessage(message)
fun sendRttMessage(message: String, isFinalized: Boolean) {
callingSdk.sendRttMessage(message, isFinalized)
}
fun getLogFiles(): List<File> = callingSdk.getLogFiles()

Просмотреть файл

@ -86,8 +86,7 @@ internal interface CallingSDK {
//endregion
fun getRttSharedFlow(): SharedFlow<RttMessage>
fun sendRttMessage(message: String)
fun sendRttMessage(message: String, isFinalized: Boolean)
fun setTelecomManagerAudioRoute(audioRoute: Int)

Просмотреть файл

@ -549,6 +549,7 @@ internal class CallingSDKEventHandler(
senderUserRawId = it.entry.sender.identifier.rawId,
senderName = "", // it.entry.sender.displayName,
localCreatedTime = it.entry.localCreatedTime,
isLocal = it.entry.isLocal,
)
rttTextSharedFlow.emit(rttMessage)
}

Просмотреть файл

@ -146,9 +146,9 @@ internal class CallingSDKWrapper(
override fun getRttSharedFlow() = callingSDKEventHandler.getRttTextSharedFlow()
override fun sendRttMessage(message: String) {
override fun sendRttMessage(message: String, isFinalized: Boolean) {
val rttFeature = call.realTimeTextCallFeature as RealTimeTextCallFeature
rttFeature.send(message)
rttFeature.send(message, isFinalized)
}
//endregion