From 96dce63e200f560802f0857c31c9a45a97e83ac0 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Wed, 15 Feb 2023 12:59:31 +0100 Subject: [PATCH] Request assistance for breakout room Signed-off-by: Marcel Hibbe --- .../talk/activities/CallActivity.java | 11 +- .../java/com/nextcloud/talk/api/NcApi.java | 8 ++ .../talk/dagger/modules/RepositoryModule.kt | 8 ++ .../talk/dagger/modules/ViewModelModule.kt | 6 + .../talk/raisehand/RequestAssistanceModel.kt | 5 + .../raisehand/RequestAssistanceRepository.kt | 34 ++++++ .../RequestAssistanceRepositoryImpl.kt | 81 ++++++++++++ .../WithdrawRequestAssistanceModel.kt | 5 + .../raisehand/viewmodel/RaiseHandViewModel.kt | 115 ++++++++++++++++++ .../talk/ui/dialog/MoreCallActionsDialog.kt | 19 +++ .../com/nextcloud/talk/utils/ApiUtils.java | 4 + .../drawable/ic_baseline_do_not_touch_24.xml | 24 +++- app/src/main/res/values/strings.xml | 3 + 13 files changed, 315 insertions(+), 8 deletions(-) create mode 100644 app/src/main/java/com/nextcloud/talk/raisehand/RequestAssistanceModel.kt create mode 100644 app/src/main/java/com/nextcloud/talk/raisehand/RequestAssistanceRepository.kt create mode 100644 app/src/main/java/com/nextcloud/talk/raisehand/RequestAssistanceRepositoryImpl.kt create mode 100644 app/src/main/java/com/nextcloud/talk/raisehand/WithdrawRequestAssistanceModel.kt create mode 100644 app/src/main/java/com/nextcloud/talk/raisehand/viewmodel/RaiseHandViewModel.kt diff --git a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java index 13e992e90..dbf23370e 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java @@ -86,6 +86,7 @@ import com.nextcloud.talk.models.json.signaling.Signaling; import com.nextcloud.talk.models.json.signaling.SignalingOverall; import com.nextcloud.talk.models.json.signaling.settings.IceServer; import com.nextcloud.talk.models.json.signaling.settings.SignalingSettingsOverall; +import com.nextcloud.talk.raisehand.viewmodel.RaiseHandViewModel; import com.nextcloud.talk.signaling.SignalingMessageReceiver; import com.nextcloud.talk.signaling.SignalingMessageSender; import com.nextcloud.talk.ui.dialog.AudioOutputDialog; @@ -211,7 +212,7 @@ public class CallActivity extends CallBaseActivity { public WebRtcAudioManager audioManager; public CallRecordingViewModel callRecordingViewModel; -// public RaiseHandViewModel raiseHandViewModel; + public RaiseHandViewModel raiseHandViewModel; private static final String[] PERMISSIONS_CALL = { Manifest.permission.CAMERA, @@ -411,6 +412,9 @@ public class CallActivity extends CallBaseActivity { setCallState(CallStatus.CONNECTING); } + raiseHandViewModel = new ViewModelProvider(this, viewModelFactory).get((RaiseHandViewModel.class)); + raiseHandViewModel.setData(roomToken, isBreakoutRoom); + callRecordingViewModel = new ViewModelProvider(this, viewModelFactory).get((CallRecordingViewModel.class)); callRecordingViewModel.setData(roomToken); callRecordingViewModel.setRecordingState(extras.getInt(KEY_RECORDING_STATE)); @@ -1232,10 +1236,7 @@ public class CallActivity extends CallBaseActivity { public void clickHand(Boolean raise) { - if (isBreakoutRoom) { - Log.d(TAG, "send request to request help for breakout rooms."); - } -// + raiseHandViewModel.clickHandButton(); // TODO: fix how to build&send the message // if (isConnectionEstablished() && peerConnectionWrapperList != null) { diff --git a/app/src/main/java/com/nextcloud/talk/api/NcApi.java b/app/src/main/java/com/nextcloud/talk/api/NcApi.java index e2fb846ab..02c763aa8 100644 --- a/app/src/main/java/com/nextcloud/talk/api/NcApi.java +++ b/app/src/main/java/com/nextcloud/talk/api/NcApi.java @@ -587,4 +587,12 @@ public interface NcApi { @DELETE Observable stopRecording(@Header("Authorization") String authorization, @Url String url); + + @POST + Observable requestAssistance(@Header("Authorization") String authorization, + @Url String url); + + @DELETE + Observable withdrawRequestAssistance(@Header("Authorization") String authorization, + @Url String url); } diff --git a/app/src/main/java/com/nextcloud/talk/dagger/modules/RepositoryModule.kt b/app/src/main/java/com/nextcloud/talk/dagger/modules/RepositoryModule.kt index fb8c8fa0c..5fce4b3b2 100644 --- a/app/src/main/java/com/nextcloud/talk/dagger/modules/RepositoryModule.kt +++ b/app/src/main/java/com/nextcloud/talk/dagger/modules/RepositoryModule.kt @@ -33,6 +33,8 @@ import com.nextcloud.talk.data.user.UsersRepository import com.nextcloud.talk.data.user.UsersRepositoryImpl import com.nextcloud.talk.polls.repositories.PollRepository import com.nextcloud.talk.polls.repositories.PollRepositoryImpl +import com.nextcloud.talk.raisehand.RequestAssistanceRepository +import com.nextcloud.talk.raisehand.RequestAssistanceRepositoryImpl import com.nextcloud.talk.remotefilebrowser.repositories.RemoteFileBrowserItemsRepository import com.nextcloud.talk.remotefilebrowser.repositories.RemoteFileBrowserItemsRepositoryImpl import com.nextcloud.talk.repositories.callrecording.CallRecordingRepository @@ -99,4 +101,10 @@ class RepositoryModule { fun provideCallRecordingRepository(ncApi: NcApi, userProvider: CurrentUserProviderNew): CallRecordingRepository { return CallRecordingRepositoryImpl(ncApi, userProvider) } + + @Provides + fun provideRequestAssistanceRepository(ncApi: NcApi, userProvider: CurrentUserProviderNew): + RequestAssistanceRepository { + return RequestAssistanceRepositoryImpl(ncApi, userProvider) + } } diff --git a/app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt b/app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt index 990bdc32d..48228f412 100644 --- a/app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt +++ b/app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt @@ -28,6 +28,7 @@ import com.nextcloud.talk.polls.viewmodels.PollCreateViewModel import com.nextcloud.talk.polls.viewmodels.PollMainViewModel import com.nextcloud.talk.polls.viewmodels.PollResultsViewModel import com.nextcloud.talk.polls.viewmodels.PollVoteViewModel +import com.nextcloud.talk.raisehand.viewmodel.RaiseHandViewModel import com.nextcloud.talk.remotefilebrowser.viewmodels.RemoteFileBrowserItemsViewModel import com.nextcloud.talk.shareditems.viewmodels.SharedItemsViewModel import com.nextcloud.talk.viewmodels.CallRecordingViewModel @@ -95,4 +96,9 @@ abstract class ViewModelModule { @IntoMap @ViewModelKey(CallRecordingViewModel::class) abstract fun callRecordingViewModel(viewModel: CallRecordingViewModel): ViewModel + + @Binds + @IntoMap + @ViewModelKey(RaiseHandViewModel::class) + abstract fun raiseHandViewModel(viewModel: RaiseHandViewModel): ViewModel } diff --git a/app/src/main/java/com/nextcloud/talk/raisehand/RequestAssistanceModel.kt b/app/src/main/java/com/nextcloud/talk/raisehand/RequestAssistanceModel.kt new file mode 100644 index 000000000..1772cc469 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/raisehand/RequestAssistanceModel.kt @@ -0,0 +1,5 @@ +package com.nextcloud.talk.raisehand + +data class RequestAssistanceModel( + var success: Boolean +) diff --git a/app/src/main/java/com/nextcloud/talk/raisehand/RequestAssistanceRepository.kt b/app/src/main/java/com/nextcloud/talk/raisehand/RequestAssistanceRepository.kt new file mode 100644 index 000000000..2c39f9ae1 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/raisehand/RequestAssistanceRepository.kt @@ -0,0 +1,34 @@ +/* + * Nextcloud Talk application + * + * @author Marcel Hibbe + * Copyright (C) 2022 Marcel Hibbe + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.nextcloud.talk.raisehand + +import io.reactivex.Observable + +interface RequestAssistanceRepository { + + fun requestAssistance( + roomToken: String + ): Observable + + fun withdrawRequestAssistance( + roomToken: String + ): Observable +} diff --git a/app/src/main/java/com/nextcloud/talk/raisehand/RequestAssistanceRepositoryImpl.kt b/app/src/main/java/com/nextcloud/talk/raisehand/RequestAssistanceRepositoryImpl.kt new file mode 100644 index 000000000..f737b02a2 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/raisehand/RequestAssistanceRepositoryImpl.kt @@ -0,0 +1,81 @@ +/* + * Nextcloud Talk application + * + * @author Marcel Hibbe + * Copyright (C) 2022 Marcel Hibbe + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.nextcloud.talk.raisehand + +import com.nextcloud.talk.api.NcApi +import com.nextcloud.talk.data.user.model.User +import com.nextcloud.talk.models.json.generic.GenericMeta +import com.nextcloud.talk.utils.ApiUtils +import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew +import io.reactivex.Observable + +class RequestAssistanceRepositoryImpl(private val ncApi: NcApi, currentUserProvider: CurrentUserProviderNew) : + RequestAssistanceRepository { + + val currentUser: User = currentUserProvider.currentUser.blockingGet() + val credentials: String = ApiUtils.getCredentials(currentUser.username, currentUser.token) + + var apiVersion = 1 + + override fun requestAssistance(roomToken: String): Observable { + return ncApi.requestAssistance( + credentials, + ApiUtils.getUrlForRequestAssistance( + apiVersion, + currentUser.baseUrl, + roomToken + ) + ).map { mapToRequestAssistanceModel(it.ocs?.meta!!) } + } + + override fun withdrawRequestAssistance(roomToken: String): Observable { + return ncApi.withdrawRequestAssistance( + credentials, + ApiUtils.getUrlForRequestAssistance( + apiVersion, + currentUser.baseUrl, + roomToken + ) + ).map { mapToWithdrawRequestAssistanceModel(it.ocs?.meta!!) } + } + + private fun mapToRequestAssistanceModel( + response: GenericMeta + ): RequestAssistanceModel { + val success = response.statusCode == HTTP_OK + return RequestAssistanceModel( + success + ) + } + + private fun mapToWithdrawRequestAssistanceModel( + response: GenericMeta + ): WithdrawRequestAssistanceModel { + val success = response.statusCode == HTTP_OK + return WithdrawRequestAssistanceModel( + success + ) + } + + companion object { + private const val HTTP_OK: Int = 200 + } +} diff --git a/app/src/main/java/com/nextcloud/talk/raisehand/WithdrawRequestAssistanceModel.kt b/app/src/main/java/com/nextcloud/talk/raisehand/WithdrawRequestAssistanceModel.kt new file mode 100644 index 000000000..88b7f74b4 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/raisehand/WithdrawRequestAssistanceModel.kt @@ -0,0 +1,5 @@ +package com.nextcloud.talk.raisehand + +data class WithdrawRequestAssistanceModel( + var success: Boolean +) diff --git a/app/src/main/java/com/nextcloud/talk/raisehand/viewmodel/RaiseHandViewModel.kt b/app/src/main/java/com/nextcloud/talk/raisehand/viewmodel/RaiseHandViewModel.kt new file mode 100644 index 000000000..c79fb0349 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/raisehand/viewmodel/RaiseHandViewModel.kt @@ -0,0 +1,115 @@ +package com.nextcloud.talk.raisehand.viewmodel + +import android.util.Log +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import com.nextcloud.talk.raisehand.RequestAssistanceModel +import com.nextcloud.talk.raisehand.RequestAssistanceRepository +import com.nextcloud.talk.raisehand.WithdrawRequestAssistanceModel +import com.nextcloud.talk.users.UserManager +import io.reactivex.Observer +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import io.reactivex.schedulers.Schedulers +import javax.inject.Inject + +class RaiseHandViewModel @Inject constructor(private val repository: RequestAssistanceRepository) : ViewModel() { + + @Inject + lateinit var userManager: UserManager + + lateinit var roomToken: String + private var isBreakoutRoom: Boolean = false + + sealed interface ViewState + + object RaisedHandState : ViewState + object LoweredHandState : ViewState + object ErrorState : ViewState + + private val _viewState: MutableLiveData = MutableLiveData(LoweredHandState) + val viewState: LiveData + get() = _viewState + + fun clickHandButton() { + when (viewState.value) { + LoweredHandState -> { + raiseHand() + } + RaisedHandState -> { + lowerHand() + } + else -> {} + } + } + + private fun raiseHand() { + _viewState.value = RaisedHandState + if (isBreakoutRoom) { + repository.requestAssistance(roomToken) + .subscribeOn(Schedulers.io()) + ?.observeOn(AndroidSchedulers.mainThread()) + ?.subscribe(RequestAssistanceObserver()) + } + } + + private fun lowerHand() { + _viewState.value = LoweredHandState + if (isBreakoutRoom) { + repository.withdrawRequestAssistance(roomToken) + .subscribeOn(Schedulers.io()) + ?.observeOn(AndroidSchedulers.mainThread()) + ?.subscribe(WithdrawRequestAssistanceObserver()) + } + } + + fun setData(roomToken: String, isBreakoutRoom: Boolean) { + this.roomToken = roomToken + this.isBreakoutRoom = isBreakoutRoom + } + + inner class RequestAssistanceObserver : Observer { + override fun onSubscribe(d: Disposable) { + // unused atm + } + + override fun onNext(requestAssistanceModel: RequestAssistanceModel) { + // RaisedHandState was already set because it's also used for signaling message + Log.d(TAG, "requestAssistance successful") + } + + override fun onError(e: Throwable) { + Log.e(TAG, "failure in RequestAssistanceObserver", e) + _viewState.value = ErrorState + } + + override fun onComplete() { + // dismiss() + } + } + + inner class WithdrawRequestAssistanceObserver : Observer { + override fun onSubscribe(d: Disposable) { + // unused atm + } + + override fun onNext(withdrawRequestAssistanceModel: WithdrawRequestAssistanceModel) { + // LoweredHandState was already set because it's also used for signaling message + Log.d(TAG, "withdrawRequestAssistance successful") + } + + override fun onError(e: Throwable) { + Log.e(TAG, "failure in WithdrawRequestAssistanceObserver", e) + _viewState.value = ErrorState + } + + override fun onComplete() { + // dismiss() + } + } + + companion object { + private val TAG = RaiseHandViewModel::class.java.simpleName + } +} diff --git a/app/src/main/java/com/nextcloud/talk/ui/dialog/MoreCallActionsDialog.kt b/app/src/main/java/com/nextcloud/talk/ui/dialog/MoreCallActionsDialog.kt index ae78c530b..3da2934b9 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/dialog/MoreCallActionsDialog.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/dialog/MoreCallActionsDialog.kt @@ -32,6 +32,7 @@ import com.nextcloud.talk.R import com.nextcloud.talk.activities.CallActivity import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.databinding.DialogMoreCallActionsBinding +import com.nextcloud.talk.raisehand.viewmodel.RaiseHandViewModel import com.nextcloud.talk.ui.theme.ViewThemeUtils import com.nextcloud.talk.viewmodels.CallRecordingViewModel import javax.inject.Inject @@ -122,6 +123,24 @@ class MoreCallActionsDialog(private val callActivity: CallActivity) : BottomShee } } } + + callActivity.raiseHandViewModel.viewState.observe(this) { state -> + when (state) { + is RaiseHandViewModel.RaisedHandState -> { + binding.raiseHandText.text = context.getText(R.string.lower_hand) + binding.raiseHandIcon.setImageDrawable( + ContextCompat.getDrawable(context, R.drawable.ic_baseline_do_not_touch_24) + ) + } + is RaiseHandViewModel.LoweredHandState -> { + binding.raiseHandText.text = context.getText(R.string.raise_hand) + binding.raiseHandIcon.setImageDrawable( + ContextCompat.getDrawable(context, R.drawable.ic_hand_back_left) + ) + } + else -> {} + } + } } companion object { diff --git a/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java b/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java index fe40815d9..6c2dd557b 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java +++ b/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java @@ -498,4 +498,8 @@ public class ApiUtils { public static String getUrlForRecording(int version, String baseUrl, String token) { return getUrlForApi(version, baseUrl) + "/recording/" + token; } + + public static String getUrlForRequestAssistance(int version, String baseUrl, String token) { + return getUrlForApi(version, baseUrl) + "/breakout-rooms/" + token + "/request-assistance"; + } } diff --git a/app/src/main/res/drawable/ic_baseline_do_not_touch_24.xml b/app/src/main/res/drawable/ic_baseline_do_not_touch_24.xml index 6f844e82d..a6ba60c39 100644 --- a/app/src/main/res/drawable/ic_baseline_do_not_touch_24.xml +++ b/app/src/main/res/drawable/ic_baseline_do_not_touch_24.xml @@ -1,5 +1,23 @@ - + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e19b85751..6b2eb1dca 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -573,6 +573,9 @@ Do you really want to stop the recording? The call is being recorded + Raise hand + Lower hand + Media File