mirror of
https://github.com/nextcloud/talk-android
synced 2025-06-20 12:09:45 +01:00
Handle more call recording states
more call recording states are: 3 = Starting video recording 4 = Starting audio recording 5 = Recording failed these actions were added: - Show grey recording icon to moderators if recording is starting - Show toast to moderators if recording failed - Add system message for recording failed Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
This commit is contained in:
parent
c1b79ac4dd
commit
499e022114
@ -445,30 +445,44 @@ public class CallActivity extends CallBaseActivity {
|
|||||||
|
|
||||||
callRecordingViewModel.getViewState().observe(this, viewState -> {
|
callRecordingViewModel.getViewState().observe(this, viewState -> {
|
||||||
if (viewState instanceof CallRecordingViewModel.RecordingStartedState) {
|
if (viewState instanceof CallRecordingViewModel.RecordingStartedState) {
|
||||||
|
binding.callRecordingIndicator.setImageResource(R.drawable.record_stop);
|
||||||
binding.callRecordingIndicator.setVisibility(View.VISIBLE);
|
binding.callRecordingIndicator.setVisibility(View.VISIBLE);
|
||||||
if (((CallRecordingViewModel.RecordingStartedState) viewState).getShowStartedInfo()) {
|
if (((CallRecordingViewModel.RecordingStartedState) viewState).getShowStartedInfo()) {
|
||||||
VibrationUtils.INSTANCE.vibrateShort(context);
|
VibrationUtils.INSTANCE.vibrateShort(context);
|
||||||
Toast.makeText(context, context.getResources().getString(R.string.record_active_info), Toast.LENGTH_LONG).show();
|
Toast.makeText(context, context.getResources().getString(R.string.record_active_info), Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
|
} else if (viewState instanceof CallRecordingViewModel.RecordingStartingState) {
|
||||||
|
if (isAllowedToStartOrStopRecording()) {
|
||||||
|
binding.callRecordingIndicator.setImageResource(R.drawable.record_starting);
|
||||||
|
binding.callRecordingIndicator.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
binding.callRecordingIndicator.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
} else if (viewState instanceof CallRecordingViewModel.RecordingConfirmStopState) {
|
} else if (viewState instanceof CallRecordingViewModel.RecordingConfirmStopState) {
|
||||||
MaterialAlertDialogBuilder dialogBuilder = new MaterialAlertDialogBuilder(this)
|
if (isAllowedToStartOrStopRecording()) {
|
||||||
.setTitle(R.string.record_stop_confirm_title)
|
MaterialAlertDialogBuilder dialogBuilder = new MaterialAlertDialogBuilder(this)
|
||||||
.setMessage(R.string.record_stop_confirm_message)
|
.setTitle(R.string.record_stop_confirm_title)
|
||||||
.setPositiveButton(R.string.record_stop_description,
|
.setMessage(R.string.record_stop_confirm_message)
|
||||||
(dialog, which) -> callRecordingViewModel.stopRecording())
|
.setPositiveButton(R.string.record_stop_description,
|
||||||
.setNegativeButton(R.string.nc_common_dismiss,
|
(dialog, which) -> callRecordingViewModel.stopRecording())
|
||||||
(dialog, which) -> callRecordingViewModel.dismissStopRecording());
|
.setNegativeButton(R.string.nc_common_dismiss,
|
||||||
viewThemeUtils.dialog.colorMaterialAlertDialogBackground(this, dialogBuilder);
|
(dialog, which) -> callRecordingViewModel.dismissStopRecording());
|
||||||
AlertDialog dialog = dialogBuilder.show();
|
viewThemeUtils.dialog.colorMaterialAlertDialogBackground(this, dialogBuilder);
|
||||||
|
AlertDialog dialog = dialogBuilder.show();
|
||||||
viewThemeUtils.platform.colorTextButtons(
|
|
||||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE),
|
|
||||||
dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
|
|
||||||
);
|
|
||||||
|
|
||||||
|
viewThemeUtils.platform.colorTextButtons(
|
||||||
|
dialog.getButton(AlertDialog.BUTTON_POSITIVE),
|
||||||
|
dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "Being in RecordingConfirmStopState as non moderator. This should not happen!");
|
||||||
|
}
|
||||||
} else if (viewState instanceof CallRecordingViewModel.RecordingErrorState) {
|
} else if (viewState instanceof CallRecordingViewModel.RecordingErrorState) {
|
||||||
Toast.makeText(context, context.getResources().getString(R.string.nc_common_error_sorry),
|
if (isAllowedToStartOrStopRecording()) {
|
||||||
Toast.LENGTH_LONG).show();
|
Toast.makeText(context, context.getResources().getString(R.string.record_failed_info),
|
||||||
|
Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
binding.callRecordingIndicator.setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
binding.callRecordingIndicator.setVisibility(View.GONE);
|
binding.callRecordingIndicator.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
@ -603,7 +617,14 @@ public class CallActivity extends CallBaseActivity {
|
|||||||
|
|
||||||
binding.callRecordingIndicator.setOnClickListener(l -> {
|
binding.callRecordingIndicator.setOnClickListener(l -> {
|
||||||
if (isAllowedToStartOrStopRecording()) {
|
if (isAllowedToStartOrStopRecording()) {
|
||||||
callRecordingViewModel.clickRecordButton();
|
if (callRecordingViewModel.getViewState().getValue() instanceof CallRecordingViewModel.RecordingStartingState) {
|
||||||
|
if (moreCallActionsDialog == null) {
|
||||||
|
moreCallActionsDialog = new MoreCallActionsDialog(this);
|
||||||
|
}
|
||||||
|
moreCallActionsDialog.show();
|
||||||
|
} else {
|
||||||
|
callRecordingViewModel.clickRecordButton();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(context, context.getResources().getString(R.string.record_active_info), Toast.LENGTH_LONG).show();
|
Toast.makeText(context, context.getResources().getString(R.string.record_active_info), Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
|
@ -530,6 +530,7 @@ data class ChatMessage(
|
|||||||
RECORDING_STOPPED,
|
RECORDING_STOPPED,
|
||||||
AUDIO_RECORDING_STARTED,
|
AUDIO_RECORDING_STARTED,
|
||||||
AUDIO_RECORDING_STOPPED,
|
AUDIO_RECORDING_STOPPED,
|
||||||
|
RECORDING_FAILED,
|
||||||
BREAKOUT_ROOMS_STARTED,
|
BREAKOUT_ROOMS_STARTED,
|
||||||
BREAKOUT_ROOMS_STOPPED
|
BREAKOUT_ROOMS_STOPPED
|
||||||
}
|
}
|
||||||
|
@ -78,6 +78,7 @@ import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.REACTIO
|
|||||||
import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.REACTION_REVOKED
|
import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.REACTION_REVOKED
|
||||||
import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.READ_ONLY
|
import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.READ_ONLY
|
||||||
import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.READ_ONLY_OFF
|
import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.READ_ONLY_OFF
|
||||||
|
import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.RECORDING_FAILED
|
||||||
import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.RECORDING_STARTED
|
import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.RECORDING_STARTED
|
||||||
import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.RECORDING_STOPPED
|
import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.RECORDING_STOPPED
|
||||||
import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.USER_ADDED
|
import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.USER_ADDED
|
||||||
@ -143,6 +144,7 @@ class EnumSystemMessageTypeConverter : StringBasedTypeConverter<ChatMessage.Syst
|
|||||||
"recording_stopped" -> RECORDING_STOPPED
|
"recording_stopped" -> RECORDING_STOPPED
|
||||||
"audio_recording_started" -> AUDIO_RECORDING_STARTED
|
"audio_recording_started" -> AUDIO_RECORDING_STARTED
|
||||||
"audio_recording_stopped" -> AUDIO_RECORDING_STOPPED
|
"audio_recording_stopped" -> AUDIO_RECORDING_STOPPED
|
||||||
|
"recording_failed" -> RECORDING_FAILED
|
||||||
"breakout_rooms_started" -> BREAKOUT_ROOMS_STARTED
|
"breakout_rooms_started" -> BREAKOUT_ROOMS_STARTED
|
||||||
"breakout_rooms_stopped" -> BREAKOUT_ROOMS_STOPPED
|
"breakout_rooms_stopped" -> BREAKOUT_ROOMS_STOPPED
|
||||||
else -> DUMMY
|
else -> DUMMY
|
||||||
@ -206,6 +208,7 @@ class EnumSystemMessageTypeConverter : StringBasedTypeConverter<ChatMessage.Syst
|
|||||||
RECORDING_STOPPED -> "recording_stopped"
|
RECORDING_STOPPED -> "recording_stopped"
|
||||||
AUDIO_RECORDING_STARTED -> "audio_recording_started"
|
AUDIO_RECORDING_STARTED -> "audio_recording_started"
|
||||||
AUDIO_RECORDING_STOPPED -> "audio_recording_stopped"
|
AUDIO_RECORDING_STOPPED -> "audio_recording_stopped"
|
||||||
|
RECORDING_FAILED -> "recording_failed"
|
||||||
BREAKOUT_ROOMS_STARTED -> "breakout_rooms_started"
|
BREAKOUT_ROOMS_STARTED -> "breakout_rooms_started"
|
||||||
BREAKOUT_ROOMS_STOPPED -> "breakout_rooms_stopped"
|
BREAKOUT_ROOMS_STOPPED -> "breakout_rooms_stopped"
|
||||||
else -> ""
|
else -> ""
|
||||||
|
@ -94,6 +94,20 @@ class MoreCallActionsDialog(private val callActivity: CallActivity) : BottomShee
|
|||||||
private fun initObservers() {
|
private fun initObservers() {
|
||||||
callActivity.callRecordingViewModel.viewState.observe(this) { state ->
|
callActivity.callRecordingViewModel.viewState.observe(this) { state ->
|
||||||
when (state) {
|
when (state) {
|
||||||
|
is CallRecordingViewModel.RecordingStoppedState,
|
||||||
|
is CallRecordingViewModel.RecordingErrorState -> {
|
||||||
|
binding.recordCallText.text = context.getText(R.string.record_start_description)
|
||||||
|
binding.recordCallIcon.setImageDrawable(
|
||||||
|
ContextCompat.getDrawable(context, R.drawable.record_start)
|
||||||
|
)
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
is CallRecordingViewModel.RecordingStartingState -> {
|
||||||
|
binding.recordCallText.text = context.getText(R.string.record_starting)
|
||||||
|
binding.recordCallIcon.setImageDrawable(
|
||||||
|
ContextCompat.getDrawable(context, R.drawable.record_stop)
|
||||||
|
)
|
||||||
|
}
|
||||||
is CallRecordingViewModel.RecordingStartedState -> {
|
is CallRecordingViewModel.RecordingStartedState -> {
|
||||||
binding.recordCallText.text = context.getText(R.string.record_stop_description)
|
binding.recordCallText.text = context.getText(R.string.record_stop_description)
|
||||||
binding.recordCallIcon.setImageDrawable(
|
binding.recordCallIcon.setImageDrawable(
|
||||||
@ -101,18 +115,8 @@ class MoreCallActionsDialog(private val callActivity: CallActivity) : BottomShee
|
|||||||
)
|
)
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
is CallRecordingViewModel.RecordingStoppedState -> {
|
is CallRecordingViewModel.RecordingStoppingState -> {
|
||||||
binding.recordCallText.text = context.getText(R.string.record_start_description)
|
binding.recordCallText.text = context.getText(R.string.record_stopping)
|
||||||
binding.recordCallIcon.setImageDrawable(
|
|
||||||
ContextCompat.getDrawable(context, R.drawable.record_start)
|
|
||||||
)
|
|
||||||
dismiss()
|
|
||||||
}
|
|
||||||
is CallRecordingViewModel.RecordingStartLoadingState -> {
|
|
||||||
binding.recordCallText.text = context.getText(R.string.record_start_loading)
|
|
||||||
}
|
|
||||||
is CallRecordingViewModel.RecordingStopLoadingState -> {
|
|
||||||
binding.recordCallText.text = context.getText(R.string.record_stop_loading)
|
|
||||||
}
|
}
|
||||||
is CallRecordingViewModel.RecordingConfirmStopState -> {
|
is CallRecordingViewModel.RecordingConfirmStopState -> {
|
||||||
binding.recordCallText.text = context.getText(R.string.record_stop_description)
|
binding.recordCallText.text = context.getText(R.string.record_stop_description)
|
||||||
|
@ -42,11 +42,11 @@ class CallRecordingViewModel @Inject constructor(private val repository: CallRec
|
|||||||
lateinit var roomToken: String
|
lateinit var roomToken: String
|
||||||
|
|
||||||
sealed interface ViewState
|
sealed interface ViewState
|
||||||
open class RecordingStartedState(val showStartedInfo: Boolean) : ViewState
|
open class RecordingStartedState(val hasVideo: Boolean, val showStartedInfo: Boolean) : ViewState
|
||||||
|
|
||||||
object RecordingStoppedState : ViewState
|
object RecordingStoppedState : ViewState
|
||||||
object RecordingStartLoadingState : ViewState
|
open class RecordingStartingState(val hasVideo: Boolean) : ViewState
|
||||||
object RecordingStopLoadingState : ViewState
|
object RecordingStoppingState : ViewState
|
||||||
object RecordingConfirmStopState : ViewState
|
object RecordingConfirmStopState : ViewState
|
||||||
object RecordingErrorState : ViewState
|
object RecordingErrorState : ViewState
|
||||||
|
|
||||||
@ -69,6 +69,9 @@ class CallRecordingViewModel @Inject constructor(private val repository: CallRec
|
|||||||
// just show it again.
|
// just show it again.
|
||||||
_viewState.value = RecordingConfirmStopState
|
_viewState.value = RecordingConfirmStopState
|
||||||
}
|
}
|
||||||
|
is RecordingStartingState -> {
|
||||||
|
stopRecording()
|
||||||
|
}
|
||||||
RecordingErrorState -> {
|
RecordingErrorState -> {
|
||||||
stopRecording()
|
stopRecording()
|
||||||
}
|
}
|
||||||
@ -77,7 +80,7 @@ class CallRecordingViewModel @Inject constructor(private val repository: CallRec
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun startRecording() {
|
private fun startRecording() {
|
||||||
_viewState.value = RecordingStartLoadingState
|
_viewState.value = RecordingStartingState(true)
|
||||||
repository.startRecording(roomToken)
|
repository.startRecording(roomToken)
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
?.observeOn(AndroidSchedulers.mainThread())
|
?.observeOn(AndroidSchedulers.mainThread())
|
||||||
@ -85,7 +88,7 @@ class CallRecordingViewModel @Inject constructor(private val repository: CallRec
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun stopRecording() {
|
fun stopRecording() {
|
||||||
_viewState.value = RecordingStopLoadingState
|
_viewState.value = RecordingStoppingState
|
||||||
repository.stopRecording(roomToken)
|
repository.stopRecording(roomToken)
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
?.observeOn(AndroidSchedulers.mainThread())
|
?.observeOn(AndroidSchedulers.mainThread())
|
||||||
@ -93,7 +96,7 @@ class CallRecordingViewModel @Inject constructor(private val repository: CallRec
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun dismissStopRecording() {
|
fun dismissStopRecording() {
|
||||||
_viewState.value = RecordingStartedState(false)
|
_viewState.value = RecordingStartedState(true, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCleared() {
|
override fun onCleared() {
|
||||||
@ -109,8 +112,11 @@ class CallRecordingViewModel @Inject constructor(private val repository: CallRec
|
|||||||
fun setRecordingState(state: Int) {
|
fun setRecordingState(state: Int) {
|
||||||
when (state) {
|
when (state) {
|
||||||
RECORDING_STOPPED_CODE -> _viewState.value = RecordingStoppedState
|
RECORDING_STOPPED_CODE -> _viewState.value = RecordingStoppedState
|
||||||
RECORDING_STARTED_VIDEO_CODE -> _viewState.value = RecordingStartedState(true)
|
RECORDING_STARTED_VIDEO_CODE -> _viewState.value = RecordingStartedState(true, true)
|
||||||
RECORDING_STARTED_AUDIO_CODE -> _viewState.value = RecordingStartedState(true)
|
RECORDING_STARTED_AUDIO_CODE -> _viewState.value = RecordingStartedState(false, true)
|
||||||
|
RECORDING_STARTING_VIDEO_CODE -> _viewState.value = RecordingStartingState(true)
|
||||||
|
RECORDING_STARTING_AUDIO_CODE -> _viewState.value = RecordingStartingState(false)
|
||||||
|
RECORDING_FAILED_CODE -> _viewState.value = RecordingErrorState
|
||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -160,5 +166,8 @@ class CallRecordingViewModel @Inject constructor(private val repository: CallRec
|
|||||||
const val RECORDING_STOPPED_CODE = 0
|
const val RECORDING_STOPPED_CODE = 0
|
||||||
const val RECORDING_STARTED_VIDEO_CODE = 1
|
const val RECORDING_STARTED_VIDEO_CODE = 1
|
||||||
const val RECORDING_STARTED_AUDIO_CODE = 2
|
const val RECORDING_STARTED_AUDIO_CODE = 2
|
||||||
|
const val RECORDING_STARTING_VIDEO_CODE = 3
|
||||||
|
const val RECORDING_STARTING_AUDIO_CODE = 4
|
||||||
|
const val RECORDING_FAILED_CODE = 5
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
9
app/src/main/res/drawable/record_starting.xml
Normal file
9
app/src/main/res/drawable/record_starting.xml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="@color/grey_600"
|
||||||
|
android:pathData="M12,2A10,10 0,0 0,2 12A10,10 0,0 0,12 22A10,10 0,0 0,22 12A10,10 0,0 0,12 2M9,9H15V15H9"/>
|
||||||
|
</vector>
|
@ -582,12 +582,13 @@ How to translate with transifex:
|
|||||||
|
|
||||||
<!-- Call recording -->
|
<!-- Call recording -->
|
||||||
<string name="record_start_description">Start recording</string>
|
<string name="record_start_description">Start recording</string>
|
||||||
<string name="record_start_loading">Starting …</string>
|
<string name="record_starting">Cancel recording start</string>
|
||||||
<string name="record_stop_description">Stop recording</string>
|
<string name="record_stop_description">Stop recording</string>
|
||||||
<string name="record_stop_loading">Stopping …</string>
|
<string name="record_stopping">Stopping recording …</string>
|
||||||
<string name="record_stop_confirm_title">Stop Call recording</string>
|
<string name="record_stop_confirm_title">Stop Call recording</string>
|
||||||
<string name="record_stop_confirm_message">Do you really want to stop the recording?</string>
|
<string name="record_stop_confirm_message">Do you really want to stop the recording?</string>
|
||||||
<string name="record_active_info">The call is being recorded</string>
|
<string name="record_active_info">The call is being recorded</string>
|
||||||
|
<string name="record_failed_info">The recording failed. Please contact your administrator.</string>
|
||||||
|
|
||||||
<!-- Shared items -->
|
<!-- Shared items -->
|
||||||
<string name="shared_items_media">Media</string>
|
<string name="shared_items_media">Media</string>
|
||||||
|
@ -21,7 +21,7 @@ class CallRecordingViewModelTest : AbstractViewModelTest() {
|
|||||||
viewModel.setData("foo")
|
viewModel.setData("foo")
|
||||||
viewModel.clickRecordButton()
|
viewModel.clickRecordButton()
|
||||||
|
|
||||||
Assert.equals(CallRecordingViewModel.RecordingStartLoadingState, viewModel.viewState.value)
|
Assert.equals(CallRecordingViewModel.RecordingStartingState(true), viewModel.viewState.value)
|
||||||
|
|
||||||
// fake to execute setRecordingState which would be triggered by signaling message
|
// fake to execute setRecordingState which would be triggered by signaling message
|
||||||
viewModel.setRecordingState(CallRecordingViewModel.RECORDING_STARTED_VIDEO_CODE)
|
viewModel.setRecordingState(CallRecordingViewModel.RECORDING_STARTED_VIDEO_CODE)
|
||||||
@ -78,7 +78,7 @@ class CallRecordingViewModelTest : AbstractViewModelTest() {
|
|||||||
viewModel.dismissStopRecording()
|
viewModel.dismissStopRecording()
|
||||||
|
|
||||||
Assert.equals(
|
Assert.equals(
|
||||||
CallRecordingViewModel.RecordingStartedState(false).javaClass,
|
CallRecordingViewModel.RecordingStartedState(true, false).javaClass,
|
||||||
viewModel.viewState.value?.javaClass
|
viewModel.viewState.value?.javaClass
|
||||||
)
|
)
|
||||||
Assert.equals(
|
Assert.equals(
|
||||||
|
Loading…
Reference in New Issue
Block a user