Эх сурвалжийг харах

Merge pull request #4446 from nextcloud/coroutine_2

Migrate Rxjava to coroutines #2
Marcel Hibbe 7 сар өмнө
parent
commit
b748080360

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

@@ -195,18 +195,6 @@ public interface NcApi {
     @DELETE
     Observable<GenericOverall> removeSelfFromRoom(@Header("Authorization") String authorization, @Url String url);
 
-    /*
-        Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /room/roomToken/public
-    */
-    @POST
-    Observable<GenericOverall> makeRoomPublic(@Header("Authorization") String authorization, @Url String url);
-
-    /*
-        Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /room/roomToken/public
-    */
-    @DELETE
-    Observable<GenericOverall> makeRoomPrivate(@Header("Authorization") String authorization, @Url String url);
-
     @DELETE
     Observable<GenericOverall> deleteRoom(@Header("Authorization") String authorization, @Url String url);
 
@@ -341,18 +329,6 @@ public interface NcApi {
     Observable<Void> unregisterDeviceForNotificationsWithProxy(@Url String url,
                                                                @QueryMap Map<String, String> fields);
 
-    @FormUrlEncoded
-    @PUT
-    Observable<GenericOverall> setPassword(@Header("Authorization") String authorization,
-                                           @Url String url,
-                                           @Field("password") String password);
-
-    @FormUrlEncoded
-    @PUT
-    Observable<Response<GenericOverall>> setPassword2(@Header("Authorization") String authorization,
-                                                      @Url String url,
-                                                      @Field("password") String password);
-
     @GET
     Observable<CapabilitiesOverall> getCapabilities(@Header("Authorization") String authorization, @Url String url);
 

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

@@ -89,10 +89,10 @@ interface NcApiCoroutines {
     ): AddParticipantOverall
 
     @POST
-    suspend fun makeRoomPublic(@Header("Authorization") authorization: String?, @Url url: String): GenericOverall
+    suspend fun makeRoomPublic(@Header("Authorization") authorization: String, @Url url: String): GenericOverall
 
     @DELETE
-    suspend fun makeRoomPrivate(@Header("Authorization") authorization: String?, @Url url: String): GenericOverall
+    suspend fun makeRoomPrivate(@Header("Authorization") authorization: String, @Url url: String): GenericOverall
 
     @FormUrlEncoded
     @PUT
@@ -132,4 +132,12 @@ interface NcApiCoroutines {
         @Url url: String,
         @Body body: RequestBody
     ): GenericOverall
+
+    @FormUrlEncoded
+    @PUT
+    suspend fun setPassword2(
+        @Header("Authorization") authorization: String,
+        @Url url: String,
+        @Field("password") password: String
+    ): GenericOverall
 }

+ 2 - 3
app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationRepositoryImpl.kt

@@ -168,16 +168,15 @@ class ConversationCreationRepositoryImpl(
 
         val result: GenericOverall = if (allow) {
             ncApiCoroutines.makeRoomPublic(
-                credentials,
+                credentials!!,
                 url
             )
         } else {
             ncApiCoroutines.makeRoomPrivate(
-                credentials,
+                credentials!!,
                 url
             )
         }
-
         return result
     }
 }

+ 3 - 1
app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt

@@ -916,7 +916,9 @@ class ConversationInfoActivity :
                     it,
                     conversation!!,
                     spreedCapabilities,
-                    conversationUser
+                    conversationUser,
+                    viewModel,
+                    this
                 ).setupGuestAccess()
             }
             if (ConversationUtils.isNoteToSelfConversation(conversation!!)) {

+ 49 - 70
app/src/main/java/com/nextcloud/talk/conversationinfo/GuestAccessHelper.kt

@@ -12,9 +12,11 @@ import android.util.Log
 import android.view.LayoutInflater
 import android.view.View
 import androidx.appcompat.app.AlertDialog
+import androidx.lifecycle.LifecycleOwner
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
 import com.google.android.material.snackbar.Snackbar
 import com.nextcloud.talk.R
+import com.nextcloud.talk.conversationinfo.viewmodel.ConversationInfoViewModel
 import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.databinding.ActivityConversationInfoBinding
 import com.nextcloud.talk.databinding.DialogPasswordBinding
@@ -33,9 +35,10 @@ class GuestAccessHelper(
     private val binding: ActivityConversationInfoBinding,
     private val conversation: ConversationModel,
     private val spreedCapabilities: SpreedCapability,
-    private val conversationUser: User
+    private val conversationUser: User,
+    private val viewModel: ConversationInfoViewModel,
+    private val lifecycleOwner: LifecycleOwner
 ) {
-
     private val conversationsRepository = activity.conversationsRepository
     private val viewThemeUtils = activity.viewThemeUtils
     private val context = activity.context
@@ -61,19 +64,35 @@ class GuestAccessHelper(
         binding.guestAccessView.guestAccessSettingsAllowGuest.setOnClickListener {
             val isChecked = binding.guestAccessView.allowGuestsSwitch.isChecked
             binding.guestAccessView.allowGuestsSwitch.isChecked = !isChecked
-            conversationsRepository.allowGuests(
-                conversation.token!!,
-                !isChecked
-            ).subscribeOn(Schedulers.io())
-                .observeOn(AndroidSchedulers.mainThread()).subscribe(AllowGuestsResultObserver())
+            viewModel.allowGuests(conversation.token, !isChecked)
+            viewModel.allowGuestsViewState.observe(lifecycleOwner) { uiState ->
+                when (uiState) {
+                    is ConversationInfoViewModel.AllowGuestsUIState.Success -> {
+                        binding.guestAccessView.allowGuestsSwitch.isChecked = uiState.allow
+                        if (uiState.allow) {
+                            showAllOptions()
+                        } else {
+                            hideAllOptions()
+                        }
+                    }
+                    is ConversationInfoViewModel.AllowGuestsUIState.Error -> {
+                        val exception = uiState.exception
+                        val message = context.getString(R.string.nc_guest_access_allow_failed)
+                        Snackbar.make(binding.root, message, Snackbar.LENGTH_LONG).show()
+                        Log.e(TAG, message, exception)
+                    }
+                    ConversationInfoViewModel.AllowGuestsUIState.None -> {
+                    }
+                }
+            }
         }
 
         binding.guestAccessView.guestAccessSettingsPasswordProtection.setOnClickListener {
             val isChecked = binding.guestAccessView.passwordProtectionSwitch.isChecked
             binding.guestAccessView.passwordProtectionSwitch.isChecked = !isChecked
             if (isChecked) {
-                conversationsRepository.password("", conversation.token!!).subscribeOn(Schedulers.io())
-                    .observeOn(AndroidSchedulers.mainThread()).subscribe(PasswordResultObserver(false))
+                viewModel.setPassword("", conversation.token)
+                passwordObserver()
             } else {
                 showPasswordDialog()
             }
@@ -85,6 +104,25 @@ class GuestAccessHelper(
         }
     }
 
+    private fun passwordObserver() {
+        viewModel.passwordViewState.observe(lifecycleOwner) { uiState ->
+            when (uiState) {
+                is ConversationInfoViewModel.PasswordUiState.Success -> {
+                    // unused atm
+                }
+                is ConversationInfoViewModel.PasswordUiState.Error -> {
+                    val exception = uiState.exception
+                    val message = context.getString(R.string.nc_guest_access_password_failed)
+                    Snackbar.make(binding.root, message, Snackbar.LENGTH_LONG).show()
+                    Log.e(TAG, message, exception)
+                }
+                is ConversationInfoViewModel.PasswordUiState.None -> {
+                    // unused atm
+                }
+            }
+        }
+    }
+
     private fun showPasswordDialog() {
         val builder = MaterialAlertDialogBuilder(activity)
         builder.apply {
@@ -94,16 +132,14 @@ class GuestAccessHelper(
             setTitle(R.string.nc_guest_access_password_dialog_title)
             setPositiveButton(R.string.nc_ok) { _, _ ->
                 val password = dialogPassword.password.text.toString()
-                conversationsRepository.password(password, conversation.token!!)
-                    .subscribeOn(Schedulers.io())
-                    .observeOn(AndroidSchedulers.mainThread())
-                    .subscribe(PasswordResultObserver(true))
+                viewModel.setPassword(password, conversation.token)
             }
             setNegativeButton(R.string.nc_cancel) { _, _ ->
                 binding.guestAccessView.passwordProtectionSwitch.isChecked = false
             }
         }
         createDialog(builder)
+        passwordObserver()
     }
 
     private fun createDialog(builder: MaterialAlertDialogBuilder) {
@@ -143,32 +179,6 @@ class GuestAccessHelper(
         }
     }
 
-    inner class AllowGuestsResultObserver : Observer<ConversationsRepository.AllowGuestsResult> {
-
-        private lateinit var allowGuestsResult: ConversationsRepository.AllowGuestsResult
-
-        override fun onNext(t: ConversationsRepository.AllowGuestsResult) {
-            allowGuestsResult = t
-        }
-
-        override fun onError(e: Throwable) {
-            val message = context.getString(R.string.nc_guest_access_allow_failed)
-            Snackbar.make(binding.root, message, Snackbar.LENGTH_LONG).show()
-            Log.e(TAG, message, e)
-        }
-
-        override fun onComplete() {
-            binding.guestAccessView.allowGuestsSwitch.isChecked = allowGuestsResult.allow
-            if (allowGuestsResult.allow) {
-                showAllOptions()
-            } else {
-                hideAllOptions()
-            }
-        }
-
-        override fun onSubscribe(d: Disposable) = Unit
-    }
-
     private fun showAllOptions() {
         binding.guestAccessView.guestAccessSettingsPasswordProtection.visibility = View.VISIBLE
         if (conversationUser.capabilities?.spreedCapability?.features?.contains("sip-support") == true) {
@@ -181,37 +191,6 @@ class GuestAccessHelper(
         binding.guestAccessView.resendInvitationsButton.visibility = View.GONE
     }
 
-    inner class PasswordResultObserver(private val setPassword: Boolean) :
-        Observer<ConversationsRepository.PasswordResult> {
-
-        private lateinit var passwordResult: ConversationsRepository.PasswordResult
-
-        override fun onSubscribe(d: Disposable) = Unit
-
-        override fun onNext(t: ConversationsRepository.PasswordResult) {
-            passwordResult = t
-        }
-
-        override fun onError(e: Throwable) {
-            val message = context.getString(R.string.nc_guest_access_password_failed)
-            Snackbar.make(binding.root, message, Snackbar.LENGTH_LONG).show()
-            Log.e(TAG, message, e)
-        }
-
-        override fun onComplete() {
-            binding.guestAccessView.passwordProtectionSwitch.isChecked = passwordResult.passwordSet && setPassword
-            if (passwordResult.passwordIsWeak) {
-                val builder = MaterialAlertDialogBuilder(activity)
-                builder.apply {
-                    setTitle(R.string.nc_guest_access_password_weak_alert_title)
-                    setMessage(passwordResult.message)
-                    setPositiveButton("OK") { _, _ -> }
-                }
-                createDialog(builder)
-            }
-        }
-    }
-
     companion object {
         private val TAG = GuestAccessHelper::class.simpleName
     }

+ 46 - 0
app/src/main/java/com/nextcloud/talk/conversationinfo/viewmodel/ConversationInfoViewModel.kt

@@ -6,12 +6,14 @@
  */
 package com.nextcloud.talk.conversationinfo.viewmodel
 
+import android.annotation.SuppressLint
 import android.util.Log
 import androidx.lifecycle.DefaultLifecycleObserver
 import androidx.lifecycle.LifecycleOwner
 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.data.user.model.User
 import com.nextcloud.talk.models.domain.ConversationModel
@@ -24,6 +26,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 javax.inject.Inject
 
 class ConversationInfoViewModel @Inject constructor(
@@ -95,6 +98,14 @@ class ConversationInfoViewModel @Inject constructor(
     object GetCapabilitiesErrorState : ViewState
     open class GetCapabilitiesSuccessState(val spreedCapabilities: SpreedCapability) : ViewState
 
+    private val _allowGuestsViewState = MutableLiveData<AllowGuestsUIState>(AllowGuestsUIState.None)
+    val allowGuestsViewState: LiveData<AllowGuestsUIState>
+        get() = _allowGuestsViewState
+
+    private val _passwordViewState = MutableLiveData<PasswordUiState>(PasswordUiState.None)
+    val passwordViewState: LiveData<PasswordUiState>
+        get() = _passwordViewState
+
     private val _getCapabilitiesViewState: MutableLiveData<ViewState> = MutableLiveData(GetCapabilitiesStartState)
     val getCapabilitiesViewState: LiveData<ViewState>
         get() = _getCapabilitiesViewState
@@ -233,6 +244,29 @@ class ConversationInfoViewModel @Inject constructor(
             })
     }
 
+    fun allowGuests(token: String, allow: Boolean) {
+        viewModelScope.launch {
+            try {
+                conversationsRepository.allowGuests(token, allow)
+                _allowGuestsViewState.value = AllowGuestsUIState.Success(allow)
+            } catch (exception: Exception) {
+                _allowGuestsViewState.value = AllowGuestsUIState.Error(exception)
+            }
+        }
+    }
+
+    @SuppressLint("SuspiciousIndentation")
+    fun setPassword(password: String, token: String) {
+        viewModelScope.launch {
+            try {
+                conversationsRepository.setPassword(password, token)
+                _passwordViewState.value = PasswordUiState.Success
+            } catch (exception: Exception) {
+                _passwordViewState.value = PasswordUiState.Error(exception)
+            }
+        }
+    }
+
     suspend fun archiveConversation(user: User, token: String) {
         val apiVersion = ApiUtils.getConversationApiVersion(user, intArrayOf(ApiUtils.API_V4, ApiUtils.API_V1))
         val url = ApiUtils.getUrlForArchive(apiVersion, user.baseUrl, token)
@@ -267,4 +301,16 @@ class ConversationInfoViewModel @Inject constructor(
     companion object {
         private val TAG = ConversationInfoViewModel::class.simpleName
     }
+
+    sealed class AllowGuestsUIState {
+        data object None : AllowGuestsUIState()
+        data class Success(val allow: Boolean) : AllowGuestsUIState()
+        data class Error(val exception: Exception) : AllowGuestsUIState()
+    }
+
+    sealed class PasswordUiState {
+        data object None : PasswordUiState()
+        data object Success : PasswordUiState()
+        data class Error(val exception: Exception) : PasswordUiState()
+    }
 }

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

@@ -12,19 +12,7 @@ import io.reactivex.Observable
 
 interface ConversationsRepository {
 
-    data class AllowGuestsResult(
-        val allow: Boolean
-    )
-
-    fun allowGuests(token: String, allow: Boolean): Observable<AllowGuestsResult>
-
-    data class PasswordResult(
-        val passwordSet: Boolean,
-        val passwordIsWeak: Boolean,
-        val message: String
-    )
-
-    fun password(password: String, token: String): Observable<PasswordResult>
+    suspend fun allowGuests(token: String, allow: Boolean): GenericOverall
 
     data class ResendInvitationsResult(
         val successful: Boolean
@@ -35,5 +23,7 @@ interface ConversationsRepository {
 
     suspend fun unarchiveConversation(credentials: String, url: String): GenericOverall
 
+    suspend fun setPassword(password: String, token: String): GenericOverall
+
     fun setConversationReadOnly(credentials: String, url: String, state: Int): Observable<GenericOverall>
 }

+ 22 - 36
app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepositoryImpl.kt

@@ -7,14 +7,10 @@
  */
 package com.nextcloud.talk.repositories.conversations
 
-import com.bluelinelabs.logansquare.LoganSquare
 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.json.conversations.password.PasswordOverall
 import com.nextcloud.talk.models.json.generic.GenericOverall
-import com.nextcloud.talk.repositories.conversations.ConversationsRepository.AllowGuestsResult
-import com.nextcloud.talk.repositories.conversations.ConversationsRepository.PasswordResult
 import com.nextcloud.talk.repositories.conversations.ConversationsRepository.ResendInvitationsResult
 import com.nextcloud.talk.utils.ApiUtils
 import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew
@@ -24,8 +20,7 @@ class ConversationsRepositoryImpl(
     private val api: NcApi,
     private val coroutineApi: NcApiCoroutines,
     private val userProvider: CurrentUserProviderNew
-) :
-    ConversationsRepository {
+) : ConversationsRepository {
 
     private val user: User
         get() = userProvider.currentUser.blockingGet()
@@ -33,48 +28,27 @@ class ConversationsRepositoryImpl(
     private val credentials: String
         get() = ApiUtils.getCredentials(user.username, user.token)!!
 
-    override fun allowGuests(token: String, allow: Boolean): Observable<AllowGuestsResult> {
+    val apiVersion = ApiUtils.getConversationApiVersion(user, intArrayOf(ApiUtils.API_V4, ApiUtils.API_V1))
+
+    override suspend fun allowGuests(token: String, allow: Boolean): GenericOverall {
         val url = ApiUtils.getUrlForRoomPublic(
-            apiVersion(),
+            apiVersion,
             user.baseUrl!!,
             token
         )
 
-        val apiObservable = if (allow) {
-            api.makeRoomPublic(
+        val result: GenericOverall = if (allow) {
+            coroutineApi.makeRoomPublic(
                 credentials,
                 url
             )
         } else {
-            api.makeRoomPrivate(
+            coroutineApi.makeRoomPrivate(
                 credentials,
                 url
             )
         }
-
-        return apiObservable.map { AllowGuestsResult(it.ocs!!.meta!!.statusCode == STATUS_CODE_OK && allow) }
-    }
-
-    override fun password(password: String, token: String): Observable<PasswordResult> {
-        val apiObservable = api.setPassword2(
-            credentials,
-            ApiUtils.getUrlForRoomPassword(
-                apiVersion(),
-                user.baseUrl!!,
-                token
-            ),
-            password
-        )
-        return apiObservable.map {
-            val passwordPolicyMessage = if (it.code() == STATUS_CODE_BAD_REQUEST) {
-                LoganSquare.parse(it.errorBody()!!.string(), PasswordOverall::class.java).ocs!!.data!!
-                    .message!!
-            } else {
-                ""
-            }
-
-            PasswordResult(it.isSuccessful, passwordPolicyMessage.isNotEmpty(), passwordPolicyMessage)
-        }
+        return result
     }
 
     override fun resendInvitations(token: String): Observable<ResendInvitationsResult> {
@@ -104,12 +78,24 @@ class ConversationsRepositoryImpl(
         return api.setConversationReadOnly(credentials, url, state)
     }
 
+    override suspend fun setPassword(password: String, token: String): GenericOverall {
+        val result = coroutineApi.setPassword(
+            credentials,
+            ApiUtils.getUrlForRoomPassword(
+                apiVersion,
+                user.baseUrl!!,
+                token
+            ),
+            password
+        )
+        return result
+    }
+
     private fun apiVersion(): Int {
         return ApiUtils.getConversationApiVersion(user, intArrayOf(ApiUtils.API_V4))
     }
 
     companion object {
         const val STATUS_CODE_OK = 200
-        const val STATUS_CODE_BAD_REQUEST = 400
     }
 }