فهرست منبع

Merge pull request #4455 from nextcloud/coroutine_3

Migrate Rxjava to Coroutines
Sowjanya Kota 5 ماه پیش
والد
کامیت
8228f770b9
16فایلهای تغییر یافته به همراه237 افزوده شده و 292 حذف شده
  1. 0 29
      app/src/main/java/com/nextcloud/talk/api/NcApi.java
  2. 5 2
      app/src/main/java/com/nextcloud/talk/api/NcApiCoroutines.kt
  3. 14 10
      app/src/main/java/com/nextcloud/talk/conversation/RenameConversationDialogFragment.kt
  4. 0 3
      app/src/main/java/com/nextcloud/talk/conversation/repository/ConversationRepository.kt
  5. 0 19
      app/src/main/java/com/nextcloud/talk/conversation/repository/ConversationRepositoryImpl.kt
  6. 0 70
      app/src/main/java/com/nextcloud/talk/conversation/viewmodel/RenameConversationViewModel.kt
  7. 25 37
      app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt
  8. 42 29
      app/src/main/java/com/nextcloud/talk/conversationinfo/viewmodel/ConversationInfoViewModel.kt
  9. 45 82
      app/src/main/java/com/nextcloud/talk/conversationinfoedit/ConversationInfoEditActivity.kt
  10. 5 0
      app/src/main/java/com/nextcloud/talk/conversationinfoedit/data/ConversationInfoEditRepository.kt
  11. 36 1
      app/src/main/java/com/nextcloud/talk/conversationinfoedit/data/ConversationInfoEditRepositoryImpl.kt
  12. 49 0
      app/src/main/java/com/nextcloud/talk/conversationinfoedit/viewmodel/ConversationInfoEditViewModel.kt
  13. 2 1
      app/src/main/java/com/nextcloud/talk/dagger/modules/RepositoryModule.kt
  14. 0 6
      app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt
  15. 3 1
      app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepository.kt
  16. 11 2
      app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepositoryImpl.kt

+ 0 - 29
app/src/main/java/com/nextcloud/talk/api/NcApi.java

@@ -118,26 +118,6 @@ public interface NcApi {
                                        @Url String url,
                                        @QueryMap Map<String, String> options);
 
-    /*
-        QueryMap items are as follows:
-            - "roomName" : "newName"
-
-        Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /room/roomToken
-     */
-
-    @FormUrlEncoded
-    @PUT
-    Observable<GenericOverall> renameRoom(@Header("Authorization") String authorization,
-                                          @Url String url,
-                                          @Field("roomName") String roomName);
-
-
-    @FormUrlEncoded
-    @PUT
-    Observable<GenericOverall> setConversationDescription(@Header("Authorization") String authorization,
-                                                          @Url String url,
-                                                          @Field("description") String description);
-
     /*
         QueryMap items are as follows:
             - "newParticipant" : "user"
@@ -413,12 +393,6 @@ public interface NcApi {
                                                     @Url String url,
                                                     @Field("level") int level);
 
-    @FormUrlEncoded
-    @PUT
-    Observable<GenericOverall> setConversationReadOnly(@Header("Authorization") String authorization,
-                                                @Url String url,
-                                                @Field("state") int state);
-
     @FormUrlEncoded
     @POST
     Observable<GenericOverall> createRemoteShare(@Nullable @Header("Authorization") String authorization,
@@ -492,9 +466,6 @@ public interface NcApi {
                                             @Field("objectId") String objectId,
                                             @Field("metaData") String metaData);
 
-    @DELETE
-    Observable<GenericOverall> clearChatHistory(@Header("Authorization") String authorization, @Url String url);
-
     @FormUrlEncoded
     @POST
     Observable<GenericOverall> notificationCalls(@Header("Authorization") String authorization,

+ 5 - 2
app/src/main/java/com/nextcloud/talk/api/NcApiCoroutines.kt

@@ -133,11 +133,14 @@ interface NcApiCoroutines {
         @Body body: RequestBody
     ): GenericOverall
 
+    @DELETE
+    suspend fun clearChatHistory(@Header("Authorization") authorization: String, @Url url: String): GenericOverall
+
     @FormUrlEncoded
     @PUT
-    suspend fun setPassword2(
+    suspend fun setConversationReadOnly(
         @Header("Authorization") authorization: String,
         @Url url: String,
-        @Field("password") password: String
+        @Field("state") state: Int
     ): GenericOverall
 }

+ 14 - 10
app/src/main/java/com/nextcloud/talk/conversation/RenameConversationDialogFragment.kt

@@ -27,7 +27,7 @@ import com.google.android.material.snackbar.Snackbar
 import com.nextcloud.android.common.ui.theme.utils.ColorRole
 import com.nextcloud.talk.R
 import com.nextcloud.talk.application.NextcloudTalkApplication
-import com.nextcloud.talk.conversation.viewmodel.RenameConversationViewModel
+import com.nextcloud.talk.conversationinfoedit.viewmodel.ConversationInfoEditViewModel
 import com.nextcloud.talk.conversationlist.ConversationsListActivity
 import com.nextcloud.talk.databinding.DialogRenameConversationBinding
 import com.nextcloud.talk.events.ConversationsListFetchDataEvent
@@ -49,7 +49,7 @@ class RenameConversationDialogFragment : DialogFragment() {
     lateinit var eventBus: EventBus
 
     private lateinit var binding: DialogRenameConversationBinding
-    private lateinit var viewModel: RenameConversationViewModel
+    private lateinit var viewModel: ConversationInfoEditViewModel
 
     private var emojiPopup: EmojiPopup? = null
 
@@ -61,7 +61,7 @@ class RenameConversationDialogFragment : DialogFragment() {
 
         NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
 
-        viewModel = ViewModelProvider(this, viewModelFactory)[RenameConversationViewModel::class.java]
+        viewModel = ViewModelProvider(this, viewModelFactory)[ConversationInfoEditViewModel::class.java]
         roomToken = arguments?.getString(KEY_ROOM_TOKEN)!!
         initialName = arguments?.getString(INITIAL_NAME)!!
     }
@@ -102,7 +102,7 @@ class RenameConversationDialogFragment : DialogFragment() {
         val positiveButton = (dialog as AlertDialog).getButton(AlertDialog.BUTTON_POSITIVE)
         positiveButton.isEnabled = false
         positiveButton.setOnClickListener {
-            viewModel.renameConversation(roomToken, binding.textEdit.text.toString())
+            viewModel.renameRoom(roomToken, binding.textEdit.text.toString())
         }
 
         themeDialog()
@@ -169,17 +169,21 @@ class RenameConversationDialogFragment : DialogFragment() {
     }
 
     private fun setupStateObserver() {
-        viewModel.viewState.observe(viewLifecycleOwner) { state ->
+        viewModel.renameRoomUiState.observe(viewLifecycleOwner) { state ->
             when (state) {
-                is RenameConversationViewModel.InitialState -> {}
-                is RenameConversationViewModel.RenamingState -> {}
-                is RenameConversationViewModel.RenamingSuccessState -> handleSuccess()
-                is RenameConversationViewModel.RenamingFailedState -> showError()
-                else -> {}
+                is ConversationInfoEditViewModel.RenameRoomUiState.None -> {
+                }
+                is ConversationInfoEditViewModel.RenameRoomUiState.Success -> {
+                    handleSuccess()
+                }
+                is ConversationInfoEditViewModel.RenameRoomUiState.Error -> {
+                    showError()
+                }
             }
         }
     }
 
+    @SuppressLint("StringFormatInvalid")
     private fun handleSuccess() {
         eventBus.post(ConversationsListFetchDataEvent())
 

+ 0 - 3
app/src/main/java/com/nextcloud/talk/conversation/repository/ConversationRepository.kt

@@ -8,13 +8,10 @@ package com.nextcloud.talk.conversation.repository
 
 import com.nextcloud.talk.models.json.conversations.ConversationEnums
 import com.nextcloud.talk.models.json.conversations.RoomOverall
-import com.nextcloud.talk.models.json.generic.GenericOverall
 import io.reactivex.Observable
 
 interface ConversationRepository {
 
-    fun renameConversation(roomToken: String, roomNameNew: String): Observable<GenericOverall>
-
     fun createConversation(
         roomName: String,
         conversationType: ConversationEnums.ConversationType?

+ 0 - 19
app/src/main/java/com/nextcloud/talk/conversation/repository/ConversationRepositoryImpl.kt

@@ -11,7 +11,6 @@ import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.models.RetrofitBucket
 import com.nextcloud.talk.models.json.conversations.ConversationEnums
 import com.nextcloud.talk.models.json.conversations.RoomOverall
-import com.nextcloud.talk.models.json.generic.GenericOverall
 import com.nextcloud.talk.utils.ApiUtils
 import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew
 import io.reactivex.Observable
@@ -24,23 +23,6 @@ class ConversationRepositoryImpl(private val ncApi: NcApi, currentUserProvider:
     val currentUser: User = currentUserProvider.currentUser.blockingGet()
     val credentials: String = ApiUtils.getCredentials(currentUser.username, currentUser.token)!!
 
-    override fun renameConversation(roomToken: String, roomNameNew: String): Observable<GenericOverall> {
-        val apiVersion = ApiUtils.getConversationApiVersion(currentUser, intArrayOf(ApiUtils.API_V4, ApiUtils.API_V1))
-
-        return ncApi.renameRoom(
-            credentials,
-            ApiUtils.getUrlForRoom(
-                apiVersion,
-                currentUser.baseUrl!!,
-                roomToken
-            ),
-            roomNameNew
-        )
-            .subscribeOn(Schedulers.io())
-            .observeOn(AndroidSchedulers.mainThread())
-            .retry(API_RETRIES)
-    }
-
     override fun createConversation(
         roomName: String,
         conversationType: ConversationEnums.ConversationType?
@@ -76,6 +58,5 @@ class ConversationRepositoryImpl(private val ncApi: NcApi, currentUserProvider:
     companion object {
         private const val ROOM_TYPE_PUBLIC = "3"
         private const val ROOM_TYPE_GROUP = "2"
-        const val API_RETRIES: Long = 3
     }
 }

+ 0 - 70
app/src/main/java/com/nextcloud/talk/conversation/viewmodel/RenameConversationViewModel.kt

@@ -1,70 +0,0 @@
-/*
- * Nextcloud Talk - Android Client
- *
- * SPDX-FileCopyrightText: 2023 Marcel Hibbe <dev@mhibbe.de>
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-package com.nextcloud.talk.conversation.viewmodel
-
-import android.util.Log
-import androidx.lifecycle.LiveData
-import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.ViewModel
-import com.nextcloud.talk.conversation.repository.ConversationRepository
-import com.nextcloud.talk.models.json.generic.GenericOverall
-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 RenameConversationViewModel @Inject constructor(private val repository: ConversationRepository) : ViewModel() {
-
-    sealed class ViewState
-    object InitialState : ViewState()
-    object RenamingState : ViewState()
-    object RenamingSuccessState : ViewState()
-    object RenamingFailedState : ViewState()
-
-    private val _viewState: MutableLiveData<ViewState> = MutableLiveData(
-        InitialState
-    )
-    val viewState: LiveData<ViewState>
-        get() = _viewState
-
-    fun renameConversation(roomToken: String, roomNameNew: String) {
-        _viewState.value = RenamingState
-
-        repository.renameConversation(
-            roomToken,
-            roomNameNew
-        )
-            .subscribeOn(Schedulers.io())
-            ?.observeOn(AndroidSchedulers.mainThread())
-            ?.subscribe(RenameConversationObserver())
-    }
-
-    inner class RenameConversationObserver : Observer<GenericOverall> {
-
-        lateinit var genericOverall: GenericOverall
-
-        override fun onSubscribe(d: Disposable) = Unit
-
-        override fun onNext(response: GenericOverall) {
-            genericOverall = response
-        }
-
-        override fun onError(e: Throwable) {
-            Log.e(TAG, "Failed to rename conversation", e)
-            _viewState.value = RenamingFailedState
-        }
-
-        override fun onComplete() {
-            _viewState.value = RenamingSuccessState
-        }
-    }
-
-    companion object {
-        private val TAG = RenameConversationViewModel::class.java.simpleName
-    }
-}

+ 25 - 37
app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt

@@ -260,12 +260,30 @@ class ConversationInfoActivity :
 
         viewModel.getConversationReadOnlyState.observe(this) { state ->
             when (state) {
-                is ConversationInfoViewModel.SetConversationReadOnlySuccessState -> {
+                is ConversationInfoViewModel.SetConversationReadOnlyViewState.Success -> {
                 }
-                is ConversationInfoViewModel.SetConversationReadOnlyErrorState -> {
+                is ConversationInfoViewModel.SetConversationReadOnlyViewState.Error -> {
                     Snackbar.make(binding.root, R.string.conversation_read_only_failed, Snackbar.LENGTH_LONG).show()
                 }
-                else -> {
+                is ConversationInfoViewModel.SetConversationReadOnlyViewState.None -> {
+                }
+            }
+        }
+
+        viewModel.clearChatHistoryViewState.observe(this) { uiState ->
+            when (uiState) {
+                is ConversationInfoViewModel.ClearChatHistoryViewState.None -> {
+                }
+                is ConversationInfoViewModel.ClearChatHistoryViewState.Success -> {
+                    Snackbar.make(
+                        binding.root,
+                        context.getString(R.string.nc_clear_history_success),
+                        Snackbar.LENGTH_LONG
+                    ).show()
+                }
+                is ConversationInfoViewModel.ClearChatHistoryViewState.Error -> {
+                    Snackbar.make(binding.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG).show()
+                    Log.e(TAG, "failed to clear chat history", uiState.exception)
                 }
             }
         }
@@ -670,7 +688,6 @@ class ConversationInfoActivity :
                                 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
                                 startActivity(intent)
                             }
-
                             WorkInfo.State.FAILED -> {
                                 val errorType = workInfo.outputData.getString("error_type")
                                 if (errorType == LeaveConversationWorker.ERROR_NO_OTHER_MODERATORS_OR_OWNERS_LEFT) {
@@ -687,7 +704,6 @@ class ConversationInfoActivity :
                                     ).show()
                                 }
                             }
-
                             else -> {
                             }
                         }
@@ -726,35 +742,7 @@ class ConversationInfoActivity :
 
     private fun clearHistory() {
         val apiVersion = ApiUtils.getChatApiVersion(spreedCapabilities, intArrayOf(1))
-
-        ncApi.clearChatHistory(
-            credentials,
-            ApiUtils.getUrlForChat(apiVersion, conversationUser.baseUrl!!, conversationToken)
-        )
-            ?.subscribeOn(Schedulers.io())
-            ?.observeOn(AndroidSchedulers.mainThread())
-            ?.subscribe(object : Observer<GenericOverall> {
-                override fun onSubscribe(d: Disposable) {
-                    // unused atm
-                }
-
-                override fun onNext(genericOverall: GenericOverall) {
-                    Snackbar.make(
-                        binding.root,
-                        context.getString(R.string.nc_clear_history_success),
-                        Snackbar.LENGTH_LONG
-                    ).show()
-                }
-
-                override fun onError(e: Throwable) {
-                    Snackbar.make(binding.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG).show()
-                    Log.e(TAG, "failed to clear chat history", e)
-                }
-
-                override fun onComplete() {
-                    // unused atm
-                }
-            })
+        viewModel.clearChatHistory(apiVersion, conversationToken)
     }
 
     private fun deleteConversation() {
@@ -849,7 +837,7 @@ class ConversationInfoActivity :
                 binding.lockConversationSwitch.isChecked = !isLocked
                 databaseStorageModule!!.saveBoolean("lock_switch", !isLocked)
                 val state = if (isLocked) 0 else 1
-                makeConversationReadOnly(conversationUser, conversationToken, state)
+                makeConversationReadOnly(conversationToken, state)
             }
         } else {
             binding.lockConversation.visibility = GONE
@@ -929,8 +917,8 @@ class ConversationInfoActivity :
         }
     }
 
-    private fun makeConversationReadOnly(conversationUser: User, roomToken: String, state: Int) {
-        viewModel.setConversationReadOnly(conversationUser, roomToken, state)
+    private fun makeConversationReadOnly(roomToken: String, state: Int) {
+        viewModel.setConversationReadOnly(roomToken, state)
     }
 
     private fun initRecordingConsentOption() {

+ 42 - 29
app/src/main/java/com/nextcloud/talk/conversationinfo/viewmodel/ConversationInfoViewModel.kt

@@ -79,13 +79,6 @@ class ConversationInfoViewModel @Inject constructor(
     val getUnBanActorState: LiveData<ViewState>
         get() = _getUnBanActorState
 
-    object SetConversationReadOnlySuccessState : ViewState
-    object SetConversationReadOnlyErrorState : ViewState
-
-    private val _getConversationReadOnlyState: MutableLiveData<ViewState> = MutableLiveData()
-    val getConversationReadOnlyState: LiveData<ViewState>
-        get() = _getConversationReadOnlyState
-
     object GetRoomStartState : ViewState
     object GetRoomErrorState : ViewState
     open class GetRoomSuccessState(val conversationModel: ConversationModel) : ViewState
@@ -110,6 +103,16 @@ class ConversationInfoViewModel @Inject constructor(
     val getCapabilitiesViewState: LiveData<ViewState>
         get() = _getCapabilitiesViewState
 
+    private val _clearChatHistoryViewState: MutableLiveData<ClearChatHistoryViewState> =
+        MutableLiveData(ClearChatHistoryViewState.None)
+    val clearChatHistoryViewState: LiveData<ClearChatHistoryViewState>
+        get() = _clearChatHistoryViewState
+
+    private val _getConversationReadOnlyState: MutableLiveData<SetConversationReadOnlyViewState> =
+        MutableLiveData(SetConversationReadOnlyViewState.None)
+    val getConversationReadOnlyState: LiveData<SetConversationReadOnlyViewState>
+        get() = _getConversationReadOnlyState
+
     fun getRoom(user: User, token: String) {
         _viewState.value = GetRoomStartState
         chatNetworkDataSource.getRoom(user, token)
@@ -196,28 +199,15 @@ class ConversationInfoViewModel @Inject constructor(
             })
     }
 
-    fun setConversationReadOnly(user: User, token: String, state: Int) {
-        val apiVersion = ApiUtils.getConversationApiVersion(user, intArrayOf(ApiUtils.API_V4, ApiUtils.API_V1))
-        val url = ApiUtils.getUrlForConversationReadOnly(apiVersion, user.baseUrl!!, token)
-        conversationsRepository.setConversationReadOnly(user.getCredentials(), url, state)
-            .subscribeOn(Schedulers.io())
-            ?.observeOn(AndroidSchedulers.mainThread())
-            ?.subscribe(object : Observer<GenericOverall> {
-                override fun onSubscribe(p0: Disposable) {
-                }
-
-                override fun onError(error: Throwable) {
-                    _getConversationReadOnlyState.value = SetConversationReadOnlyErrorState
-                }
-
-                override fun onComplete() {
-                    // unused atm
-                }
-
-                override fun onNext(p0: GenericOverall) {
-                    _getConversationReadOnlyState.value = SetConversationReadOnlySuccessState
-                }
-            })
+    fun setConversationReadOnly(roomToken: String, state: Int) {
+        viewModelScope.launch {
+            try {
+                conversationsRepository.setConversationReadOnly(roomToken, state)
+                _getConversationReadOnlyState.value = SetConversationReadOnlyViewState.Success
+            } catch (exception: Exception) {
+                _getConversationReadOnlyState.value = SetConversationReadOnlyViewState.Error(exception)
+            }
+        }
     }
 
     fun unbanActor(user: User, token: String, banId: Int) {
@@ -279,6 +269,17 @@ class ConversationInfoViewModel @Inject constructor(
         conversationsRepository.unarchiveConversation(user.getCredentials(), url)
     }
 
+    fun clearChatHistory(apiVersion: Int, roomToken: String) {
+        viewModelScope.launch {
+            try {
+                conversationsRepository.clearChatHistory(apiVersion, roomToken)
+                _clearChatHistoryViewState.value = ClearChatHistoryViewState.Success
+            } catch (exception: Exception) {
+                _clearChatHistoryViewState.value = ClearChatHistoryViewState.Error(exception)
+            }
+        }
+    }
+
     inner class GetRoomObserver : Observer<ConversationModel> {
         override fun onSubscribe(d: Disposable) {
             // unused atm
@@ -302,6 +303,18 @@ class ConversationInfoViewModel @Inject constructor(
         private val TAG = ConversationInfoViewModel::class.simpleName
     }
 
+    sealed class ClearChatHistoryViewState {
+        data object None : ClearChatHistoryViewState()
+        data object Success : ClearChatHistoryViewState()
+        data class Error(val exception: Exception) : ClearChatHistoryViewState()
+    }
+
+    sealed class SetConversationReadOnlyViewState {
+        data object None : SetConversationReadOnlyViewState()
+        data object Success : SetConversationReadOnlyViewState()
+        data class Error(val exception: Exception) : SetConversationReadOnlyViewState()
+    }
+
     sealed class AllowGuestsUIState {
         data object None : AllowGuestsUIState()
         data class Success(val allow: Boolean) : AllowGuestsUIState()

+ 45 - 82
app/src/main/java/com/nextcloud/talk/conversationinfoedit/ConversationInfoEditActivity.kt

@@ -36,15 +36,10 @@ import com.nextcloud.talk.extensions.loadUserAvatar
 import com.nextcloud.talk.models.domain.ConversationModel
 import com.nextcloud.talk.models.json.capabilities.SpreedCapability
 import com.nextcloud.talk.models.json.conversations.ConversationEnums
-import com.nextcloud.talk.models.json.generic.GenericOverall
 import com.nextcloud.talk.utils.ApiUtils
 import com.nextcloud.talk.utils.CapabilitiesUtil
 import com.nextcloud.talk.utils.PickImage
 import com.nextcloud.talk.utils.bundle.BundleKeys
-import io.reactivex.Observer
-import io.reactivex.android.schedulers.AndroidSchedulers
-import io.reactivex.disposables.Disposable
-import io.reactivex.schedulers.Schedulers
 import java.io.File
 import javax.inject.Inject
 
@@ -172,6 +167,45 @@ class ConversationInfoEditActivity : BaseActivity() {
                 else -> {}
             }
         }
+        conversationInfoEditViewModel.renameRoomUiState.observe(this) { uiState ->
+            when (uiState) {
+                is ConversationInfoEditViewModel.RenameRoomUiState.None -> {
+                }
+                is ConversationInfoEditViewModel.RenameRoomUiState.Success -> {
+                    if (CapabilitiesUtil.isConversationDescriptionEndpointAvailable(spreedCapabilities)) {
+                        saveConversationDescription()
+                    } else {
+                        finish()
+                    }
+                }
+                is ConversationInfoEditViewModel.RenameRoomUiState.Error -> {
+                    Snackbar.make(
+                        binding.root,
+                        context.getString(R.string.default_error_msg),
+                        Snackbar.LENGTH_LONG
+                    ).show()
+                    Log.e(TAG, "Error while saving conversation name", uiState.exception)
+                }
+            }
+        }
+
+        conversationInfoEditViewModel.setConversationDescriptionUiState.observe(this) { uiState ->
+            when (uiState) {
+                is ConversationInfoEditViewModel.SetConversationDescriptionUiState.None -> {
+                }
+                is ConversationInfoEditViewModel.SetConversationDescriptionUiState.Success -> {
+                    finish()
+                }
+                is ConversationInfoEditViewModel.SetConversationDescriptionUiState.Error -> {
+                    Snackbar.make(
+                        binding.root,
+                        context.getString(R.string.default_error_msg),
+                        Snackbar.LENGTH_LONG
+                    ).show()
+                    Log.e(TAG, "Error while saving conversation description", uiState.exception)
+                }
+            }
+        }
     }
 
     private fun setupAvatarOptions() {
@@ -236,87 +270,16 @@ class ConversationInfoEditActivity : BaseActivity() {
     }
 
     private fun saveConversationNameAndDescription() {
-        val apiVersion =
-            ApiUtils.getConversationApiVersion(conversationUser, intArrayOf(ApiUtils.API_V4, ApiUtils.API_V1))
-
-        ncApi.renameRoom(
-            credentials,
-            ApiUtils.getUrlForRoom(
-                apiVersion,
-                conversationUser.baseUrl!!,
-                conversation!!.token
-            ),
-            binding.conversationName.text.toString()
+        val newRoomName = binding.conversationName.text.toString()
+        conversationInfoEditViewModel.renameRoom(
+            conversation!!.token,
+            newRoomName
         )
-            .subscribeOn(Schedulers.io())
-            .observeOn(AndroidSchedulers.mainThread())
-            .retry(1)
-            .subscribe(object : Observer<GenericOverall> {
-                override fun onSubscribe(d: Disposable) {
-                    // unused atm
-                }
-
-                override fun onNext(genericOverall: GenericOverall) {
-                    if (CapabilitiesUtil.isConversationDescriptionEndpointAvailable(spreedCapabilities)) {
-                        saveConversationDescription()
-                    } else {
-                        finish()
-                    }
-                }
-
-                override fun onError(e: Throwable) {
-                    Snackbar.make(
-                        binding.root,
-                        context.getString(R.string.default_error_msg),
-                        Snackbar.LENGTH_LONG
-                    ).show()
-                    Log.e(TAG, "Error while saving conversation name", e)
-                }
-
-                override fun onComplete() {
-                    // unused atm
-                }
-            })
     }
 
     fun saveConversationDescription() {
-        val apiVersion =
-            ApiUtils.getConversationApiVersion(conversationUser, intArrayOf(ApiUtils.API_V4, ApiUtils.API_V1))
-
-        ncApi.setConversationDescription(
-            credentials,
-            ApiUtils.getUrlForConversationDescription(
-                apiVersion,
-                conversationUser.baseUrl!!,
-                conversation!!.token
-            ),
-            binding.conversationDescription.text.toString()
-        )
-            .subscribeOn(Schedulers.io())
-            .observeOn(AndroidSchedulers.mainThread())
-            .retry(1)
-            .subscribe(object : Observer<GenericOverall> {
-                override fun onSubscribe(d: Disposable) {
-                    // unused atm
-                }
-
-                override fun onNext(genericOverall: GenericOverall) {
-                    finish()
-                }
-
-                override fun onError(e: Throwable) {
-                    Snackbar.make(
-                        binding.root,
-                        context.getString(R.string.default_error_msg),
-                        Snackbar.LENGTH_LONG
-                    ).show()
-                    Log.e(TAG, "Error while saving conversation description", e)
-                }
-
-                override fun onComplete() {
-                    // unused atm
-                }
-            })
+        val conversationDescription = binding.conversationDescription.text.toString()
+        conversationInfoEditViewModel.setConversationDescription(conversation!!.token, conversationDescription)
     }
 
     private fun handleResult(result: ActivityResult, onResult: (result: ActivityResult) -> Unit) {

+ 5 - 0
app/src/main/java/com/nextcloud/talk/conversationinfoedit/data/ConversationInfoEditRepository.kt

@@ -8,6 +8,7 @@ package com.nextcloud.talk.conversationinfoedit.data
 
 import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.models.domain.ConversationModel
+import com.nextcloud.talk.models.json.generic.GenericOverall
 import io.reactivex.Observable
 import java.io.File
 
@@ -16,4 +17,8 @@ interface ConversationInfoEditRepository {
     fun uploadConversationAvatar(user: User, file: File, roomToken: String): Observable<ConversationModel>
 
     fun deleteConversationAvatar(user: User, roomToken: String): Observable<ConversationModel>
+
+    suspend fun renameConversation(roomToken: String, roomNameNew: String): GenericOverall
+
+    suspend fun setConversationDescription(roomToken: String, conversationDescription: String?): GenericOverall
 }

+ 36 - 1
app/src/main/java/com/nextcloud/talk/conversationinfoedit/data/ConversationInfoEditRepositoryImpl.kt

@@ -7,8 +7,10 @@
 package com.nextcloud.talk.conversationinfoedit.data
 
 import com.nextcloud.talk.api.NcApi
+import com.nextcloud.talk.api.NcApiCoroutines
 import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.models.domain.ConversationModel
+import com.nextcloud.talk.models.json.generic.GenericOverall
 import com.nextcloud.talk.utils.ApiUtils
 import com.nextcloud.talk.utils.Mimetype
 import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew
@@ -18,7 +20,11 @@ import okhttp3.MultipartBody
 import okhttp3.RequestBody.Companion.asRequestBody
 import java.io.File
 
-class ConversationInfoEditRepositoryImpl(private val ncApi: NcApi, currentUserProvider: CurrentUserProviderNew) :
+class ConversationInfoEditRepositoryImpl(
+    private val ncApi: NcApi,
+    private val ncApiCoroutines: NcApiCoroutines,
+    currentUserProvider: CurrentUserProviderNew
+) :
     ConversationInfoEditRepository {
 
     val currentUser: User = currentUserProvider.currentUser.blockingGet()
@@ -53,4 +59,33 @@ class ConversationInfoEditRepositoryImpl(private val ncApi: NcApi, currentUserPr
             ApiUtils.getUrlForConversationAvatar(1, user.baseUrl!!, roomToken)
         ).map { ConversationModel.mapToConversationModel(it.ocs?.data!!, user) }
     }
+
+    override suspend fun renameConversation(roomToken: String, newRoomName: String): GenericOverall {
+        val apiVersion = ApiUtils.getConversationApiVersion(currentUser, intArrayOf(ApiUtils.API_V4, ApiUtils.API_V1))
+
+        return ncApiCoroutines.renameRoom(
+            credentials,
+            ApiUtils.getUrlForRoom(
+                apiVersion,
+                currentUser.baseUrl!!,
+                roomToken
+            ),
+            newRoomName
+        )
+    }
+
+    override suspend fun setConversationDescription(
+        roomToken: String,
+        conversationDescription: String?
+    ): GenericOverall {
+        return ncApiCoroutines.setConversationDescription(
+            credentials,
+            ApiUtils.getUrlForConversationDescription(
+                apiVersion,
+                currentUser.baseUrl!!,
+                roomToken
+            ),
+            conversationDescription
+        )
+    }
 }

+ 49 - 0
app/src/main/java/com/nextcloud/talk/conversationinfoedit/viewmodel/ConversationInfoEditViewModel.kt

@@ -10,6 +10,7 @@ import android.util.Log
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
 import com.nextcloud.talk.chat.data.network.ChatNetworkDataSource
 import com.nextcloud.talk.conversationinfoedit.data.ConversationInfoEditRepository
 import com.nextcloud.talk.data.user.model.User
@@ -18,6 +19,7 @@ import io.reactivex.Observer
 import io.reactivex.android.schedulers.AndroidSchedulers
 import io.reactivex.disposables.Disposable
 import io.reactivex.schedulers.Schedulers
+import kotlinx.coroutines.launch
 import java.io.File
 import javax.inject.Inject
 
@@ -42,6 +44,15 @@ class ConversationInfoEditViewModel @Inject constructor(
     val viewState: LiveData<ViewState>
         get() = _viewState
 
+    private val _renameRoomUiState = MutableLiveData<RenameRoomUiState>(RenameRoomUiState.None)
+    val renameRoomUiState: LiveData<RenameRoomUiState>
+        get() = _renameRoomUiState
+
+    private val _setConversationDescriptionUiState =
+        MutableLiveData<SetConversationDescriptionUiState>(SetConversationDescriptionUiState.None)
+    val setConversationDescriptionUiState: LiveData<SetConversationDescriptionUiState>
+        get() = _setConversationDescriptionUiState
+
     fun getRoom(user: User, token: String) {
         _viewState.value = GetRoomStartState
         repository.getRoom(user, token)
@@ -64,6 +75,32 @@ class ConversationInfoEditViewModel @Inject constructor(
             ?.subscribe(DeleteConversationAvatarObserver())
     }
 
+    fun renameRoom(roomToken: String, newRoomName: String) {
+        viewModelScope.launch {
+            try {
+                conversationInfoEditRepository.renameConversation(roomToken, newRoomName)
+                _renameRoomUiState.value = RenameRoomUiState.Success
+            } catch (exception: Exception) {
+                _renameRoomUiState.value = RenameRoomUiState.Error(exception)
+            }
+        }
+    }
+
+    fun setConversationDescription(roomToken: String, conversationDescription: String?) {
+        viewModelScope.launch {
+            try {
+                conversationInfoEditRepository.setConversationDescription(
+                    roomToken,
+                    conversationDescription
+                )
+
+                _setConversationDescriptionUiState.value = SetConversationDescriptionUiState.Success
+            } catch (exception: Exception) {
+                _setConversationDescriptionUiState.value = SetConversationDescriptionUiState.Error(exception)
+            }
+        }
+    }
+
     inner class GetRoomObserver : Observer<ConversationModel> {
         override fun onSubscribe(d: Disposable) {
             // unused atm
@@ -124,4 +161,16 @@ class ConversationInfoEditViewModel @Inject constructor(
     companion object {
         private val TAG = ConversationInfoEditViewModel::class.simpleName
     }
+
+    sealed class RenameRoomUiState {
+        data object None : RenameRoomUiState()
+        data object Success : RenameRoomUiState()
+        data class Error(val exception: Exception) : RenameRoomUiState()
+    }
+
+    sealed class SetConversationDescriptionUiState {
+        data object None : SetConversationDescriptionUiState()
+        data object Success : SetConversationDescriptionUiState()
+        data class Error(val exception: Exception) : SetConversationDescriptionUiState()
+    }
 }

+ 2 - 1
app/src/main/java/com/nextcloud/talk/dagger/modules/RepositoryModule.kt

@@ -159,9 +159,10 @@ class RepositoryModule {
     @Provides
     fun provideConversationInfoEditRepository(
         ncApi: NcApi,
+        ncApiCoroutines: NcApiCoroutines,
         userProvider: CurrentUserProviderNew
     ): ConversationInfoEditRepository {
-        return ConversationInfoEditRepositoryImpl(ncApi, userProvider)
+        return ConversationInfoEditRepositoryImpl(ncApi, ncApiCoroutines, userProvider)
     }
 
     @Provides

+ 0 - 6
app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt

@@ -13,7 +13,6 @@ import com.nextcloud.talk.chat.viewmodels.ChatViewModel
 import com.nextcloud.talk.contacts.ContactsViewModel
 import com.nextcloud.talk.chat.viewmodels.MessageInputViewModel
 import com.nextcloud.talk.conversation.viewmodel.ConversationViewModel
-import com.nextcloud.talk.conversation.viewmodel.RenameConversationViewModel
 import com.nextcloud.talk.conversationcreation.ConversationCreationViewModel
 import com.nextcloud.talk.conversationinfo.viewmodel.ConversationInfoViewModel
 import com.nextcloud.talk.conversationinfoedit.viewmodel.ConversationInfoEditViewModel
@@ -138,11 +137,6 @@ abstract class ViewModelModule {
     @ViewModelKey(ConversationInfoEditViewModel::class)
     abstract fun conversationInfoEditViewModel(viewModel: ConversationInfoEditViewModel): ViewModel
 
-    @Binds
-    @IntoMap
-    @ViewModelKey(RenameConversationViewModel::class)
-    abstract fun renameConversationViewModel(viewModel: RenameConversationViewModel): ViewModel
-
     @Binds
     @IntoMap
     @ViewModelKey(ConversationViewModel::class)

+ 3 - 1
app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepository.kt

@@ -25,5 +25,7 @@ interface ConversationsRepository {
 
     suspend fun setPassword(password: String, token: String): GenericOverall
 
-    fun setConversationReadOnly(credentials: String, url: String, state: Int): Observable<GenericOverall>
+    suspend fun setConversationReadOnly(roomToken: String, state: Int): GenericOverall
+
+    suspend fun clearChatHistory(apiVersion: Int, roomToken: String): GenericOverall
 }

+ 11 - 2
app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepositoryImpl.kt

@@ -74,8 +74,10 @@ class ConversationsRepositoryImpl(
         return coroutineApi.unarchiveConversation(credentials, url)
     }
 
-    override fun setConversationReadOnly(credentials: String, url: String, state: Int): Observable<GenericOverall> {
-        return api.setConversationReadOnly(credentials, url, state)
+    override suspend fun setConversationReadOnly(roomToken: String, state: Int): GenericOverall {
+        val apiVersion = ApiUtils.getConversationApiVersion(user, intArrayOf(ApiUtils.API_V4, ApiUtils.API_V1))
+        val url = ApiUtils.getUrlForConversationReadOnly(apiVersion, user.baseUrl!!, roomToken)
+        return coroutineApi.setConversationReadOnly(credentials, url, state)
     }
 
     override suspend fun setPassword(password: String, token: String): GenericOverall {
@@ -91,6 +93,13 @@ class ConversationsRepositoryImpl(
         return result
     }
 
+    override suspend fun clearChatHistory(apiVersion: Int, roomToken: String): GenericOverall {
+        return coroutineApi.clearChatHistory(
+            credentials,
+            ApiUtils.getUrlForChat(apiVersion, user.baseUrl!!, roomToken)
+        )
+    }
+
     private fun apiVersion(): Int {
         return ApiUtils.getConversationApiVersion(user, intArrayOf(ApiUtils.API_V4))
     }