浏览代码

Adjusting Translation Provider

- Added 4 new model data classes
- Added the new API function to NcApi
- Implemented the changes in the Repository + ViewModel
- Implemented the changes in the Activity
- Added some helper functions to support impl

Signed-off-by: Julius Linus <julius.linus@nextcloud.com>
Julius Linus 1 年之前
父节点
当前提交
7de77ca073

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

@@ -49,6 +49,7 @@ import com.nextcloud.talk.models.json.unifiedsearch.UnifiedSearchOverall;
 import com.nextcloud.talk.models.json.userprofile.UserProfileFieldsOverall;
 import com.nextcloud.talk.models.json.userprofile.UserProfileOverall;
 import com.nextcloud.talk.polls.repositories.model.PollOverall;
+import com.nextcloud.talk.translate.repositories.model.LanguagesOverall;
 import com.nextcloud.talk.translate.repositories.model.TranslationsOverall;
 
 import java.util.List;
@@ -675,6 +676,10 @@ public interface NcApi {
                                                      @Query("toLanguage") String toLanguage,
                                                      @Nullable @Query("fromLanguage") String fromLanguage);
 
+    @GET
+    Observable<LanguagesOverall> getLanguages(@Header("Authorization") String authorization,
+                                              @Url String url);
+
     @GET
     Observable<ReminderOverall> getReminder(@Header("Authorization") String authorization,
                                             @Url String url);

+ 6 - 0
app/src/main/java/com/nextcloud/talk/translate/repositories/TranslateRepository.kt

@@ -1,5 +1,6 @@
 package com.nextcloud.talk.translate.repositories
 
+import com.nextcloud.talk.translate.repositories.model.Language
 import io.reactivex.Observable
 
 interface TranslateRepository {
@@ -11,4 +12,9 @@ interface TranslateRepository {
         toLanguage: String,
         fromLanguage: String?
     ): Observable<String>
+
+    fun getLanguages(
+        authorization: String,
+        url: String
+    ): Observable<List<Language>>
 }

+ 5 - 0
app/src/main/java/com/nextcloud/talk/translate/repositories/TranslateRepositoryImpl.kt

@@ -1,6 +1,7 @@
 package com.nextcloud.talk.translate.repositories
 
 import com.nextcloud.talk.api.NcApi
+import com.nextcloud.talk.translate.repositories.model.Language
 import io.reactivex.Observable
 import javax.inject.Inject
 
@@ -15,4 +16,8 @@ class TranslateRepositoryImpl @Inject constructor(private val ncApi: NcApi) : Tr
     ): Observable<String> {
         return ncApi.translateMessage(authorization, url, text, toLanguage, fromLanguage).map { it.ocs?.data!!.text }
     }
+
+    override fun getLanguages(authorization: String, url: String): Observable<List<Language>> {
+        return ncApi.getLanguages(authorization, url).map { it.ocs?.data?.languages }
+    }
 }

+ 41 - 0
app/src/main/java/com/nextcloud/talk/translate/repositories/model/Language.kt

@@ -0,0 +1,41 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Julius Linus
+ * Copyright (C) 2023 Julius Linus <julius.linus@nextcloud.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+package com.nextcloud.talk.translate.repositories.model
+
+import android.os.Parcelable
+import com.bluelinelabs.logansquare.annotation.JsonField
+import com.bluelinelabs.logansquare.annotation.JsonObject
+import kotlinx.parcelize.Parcelize
+
+@Parcelize
+@JsonObject
+data class Language(
+    @JsonField(name = ["from"])
+    var from: String?,
+    @JsonField(name = ["fromLabel"])
+    var fromLabel: String?,
+    @JsonField(name = ["to"])
+    var to: String?,
+    @JsonField(name = ["toLabel"])
+    var toLabel: String?
+) : Parcelable {
+    // This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject'
+    constructor() : this(null, null, null, null)
+}

+ 37 - 0
app/src/main/java/com/nextcloud/talk/translate/repositories/model/LanguagesData.kt

@@ -0,0 +1,37 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Julius Linus
+ * Copyright (C) 2023 Julius Linus <julius.linus@nextcloud.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+package com.nextcloud.talk.translate.repositories.model
+
+import android.os.Parcelable
+import com.bluelinelabs.logansquare.annotation.JsonField
+import com.bluelinelabs.logansquare.annotation.JsonObject
+import kotlinx.parcelize.Parcelize
+
+@Parcelize
+@JsonObject
+data class LanguagesData(
+    @JsonField(name = ["languageDetection"])
+    var languageDetection: Boolean?,
+    @JsonField(name = ["languages"])
+    var languages: List<Language>?
+) : Parcelable {
+    // This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject'
+    constructor() : this(null, null)
+}

+ 38 - 0
app/src/main/java/com/nextcloud/talk/translate/repositories/model/LanguagesOCS.kt

@@ -0,0 +1,38 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Julius Linus
+ * Copyright (C) 2023 Julius Linus <julius.linus@nextcloud.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+package com.nextcloud.talk.translate.repositories.model
+
+import android.os.Parcelable
+import com.bluelinelabs.logansquare.annotation.JsonField
+import com.bluelinelabs.logansquare.annotation.JsonObject
+import com.nextcloud.talk.models.json.generic.GenericMeta
+import kotlinx.parcelize.Parcelize
+
+@Parcelize
+@JsonObject
+data class LanguagesOCS(
+    @JsonField(name = ["meta"])
+    var meta: GenericMeta?,
+    @JsonField(name = ["data"])
+    var data: LanguagesData?
+) : Parcelable {
+    // This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject'
+    constructor() : this(null, null)
+}

+ 35 - 0
app/src/main/java/com/nextcloud/talk/translate/repositories/model/LanguagesOverall.kt

@@ -0,0 +1,35 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Julius Linus
+ * Copyright (C) 2023 Julius Linus <julius.linus@nextcloud.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+package com.nextcloud.talk.translate.repositories.model
+
+import android.os.Parcelable
+import com.bluelinelabs.logansquare.annotation.JsonField
+import com.bluelinelabs.logansquare.annotation.JsonObject
+import kotlinx.parcelize.Parcelize
+
+@Parcelize
+@JsonObject
+class LanguagesOverall(
+    @JsonField(name = ["ocs"])
+    var ocs: LanguagesOCS?
+) : Parcelable {
+    // This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject'
+    constructor() : this(null)
+}

+ 1 - 1
app/src/main/java/com/nextcloud/talk/translate/repositories/model/TranslateOCS.kt

@@ -27,7 +27,7 @@ import kotlinx.parcelize.Parcelize
 
 @Parcelize
 @JsonObject
-data class TranslateOCS( // TODO finish this model
+data class TranslateOCS(
     @JsonField(name = ["meta"])
     var meta: GenericMeta?,
     @JsonField(name = ["data"])

+ 43 - 32
app/src/main/java/com/nextcloud/talk/translate/ui/TranslateActivity.kt

@@ -28,6 +28,7 @@ import android.content.Context
 import android.graphics.drawable.ColorDrawable
 import android.os.Bundle
 import android.text.method.ScrollingMovementMethod
+import android.util.Log
 import android.view.View
 import android.widget.AdapterView
 import android.widget.ArrayAdapter
@@ -38,14 +39,14 @@ import com.nextcloud.talk.R
 import com.nextcloud.talk.activities.BaseActivity
 import com.nextcloud.talk.application.NextcloudTalkApplication
 import com.nextcloud.talk.databinding.ActivityTranslateBinding
+import com.nextcloud.talk.translate.repositories.model.Language
 import com.nextcloud.talk.translate.viewmodels.TranslateViewModel
 import com.nextcloud.talk.users.UserManager
 import com.nextcloud.talk.utils.bundle.BundleKeys
-import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew
-import org.json.JSONArray
 import java.util.Locale
 import javax.inject.Inject
 
+@Suppress("TooManyFunctions")
 @AutoInjector(NextcloudTalkApplication::class)
 class TranslateActivity : BaseActivity() {
 
@@ -60,6 +61,7 @@ class TranslateActivity : BaseActivity() {
 
     private var toLanguages: Array<String>? = null
     private var fromLanguages: Array<String>? = null
+    private var languages: List<Language>? = null
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
@@ -79,8 +81,20 @@ class TranslateActivity : BaseActivity() {
                     onTranslatedState(state.msg)
                 }
 
-                is TranslateViewModel.ErrorState -> {
-                    onErrorState()
+                is TranslateViewModel.TranslationErrorState -> {
+                    onTranslationErrorState()
+                }
+
+                is TranslateViewModel.LanguagesErrorState -> {
+                    onLanguagesErrorState()
+                }
+
+                is TranslateViewModel.LanguagesRetrievedState -> {
+                    Log.d(TAG, "Languages are: ${state.list}")
+                    languages = state.list
+                    getLanguageOptions()
+                    setupSpinners()
+                    setItems()
                 }
             }
         }
@@ -88,8 +102,7 @@ class TranslateActivity : BaseActivity() {
         setContentView(binding.root)
         setupSystemColors()
         setupTextViews()
-        getLanguageOptions()
-        setupSpinners()
+        viewModel.getLanguages()
         setupCopyButton()
 
         if (savedInstanceState == null) {
@@ -102,7 +115,7 @@ class TranslateActivity : BaseActivity() {
 
     override fun onResume() {
         super.onResume()
-        setItems()
+        languages?.let { setItems() }
     }
     override fun onSaveInstanceState(outState: Bundle) {
         outState.run {
@@ -155,19 +168,16 @@ class TranslateActivity : BaseActivity() {
     }
 
     private fun getLanguageOptions() {
-        val currentUser = userManager.currentUser.blockingGet()
-        val json = JSONArray((CapabilitiesUtilNew.getLanguages(currentUser) as ArrayList<*>).toArray())
-
         val fromLanguagesSet = mutableSetOf(resources.getString(R.string.translation_detect_language))
         val toLanguagesSet = mutableSetOf(resources.getString(R.string.translation_device_settings))
 
-        for (i in 0 until json.length()) {
-            val current = json.getJSONObject(i)
-            if (current.getString(FROM_ID) != Locale.getDefault().language) {
-                toLanguagesSet.add(current.getString(FROM_LABEL))
+        for (language in languages!!) {
+            val locale = Locale.getDefault().language
+            if (language.from != locale) {
+                toLanguagesSet.add(language.fromLabel!!)
             }
 
-            fromLanguagesSet.add(current.getString(TO_LABEL))
+            fromLanguagesSet.add(language.toLabel!!)
         }
 
         toLanguages = toLanguagesSet.toTypedArray()
@@ -179,7 +189,7 @@ class TranslateActivity : BaseActivity() {
         binding.toLanguageInputLayout.isEnabled = value
     }
 
-    private fun showDialog() {
+    private fun showDialog(titleInt: Int, messageInt: Int) {
         val dialogBuilder = MaterialAlertDialogBuilder(this@TranslateActivity)
             .setIcon(
                 viewThemeUtils.dialog.colorMaterialAlertDialogIcon(
@@ -187,8 +197,8 @@ class TranslateActivity : BaseActivity() {
                     R.drawable.ic_warning_white
                 )
             )
-            .setTitle(R.string.translation_error_title)
-            .setMessage(R.string.translation_error_message)
+            .setTitle(titleInt)
+            .setMessage(messageInt)
             .setPositiveButton(R.string.nc_ok) { dialog, _ ->
                 dialog.dismiss()
             }
@@ -210,18 +220,15 @@ class TranslateActivity : BaseActivity() {
         return getISOFromServer(language)
     }
 
-    private fun getISOFromServer(language: String): String {
-        val currentUser = userManager.currentUser.blockingGet()
-        val json = JSONArray((CapabilitiesUtilNew.getLanguages(currentUser) as ArrayList<*>).toArray())
-
-        for (i in 0 until json.length()) {
-            val current = json.getJSONObject(i)
-            if (current.getString(FROM_LABEL) == language) {
-                return current.getString(FROM_ID)
+    private fun getISOFromServer(label: String): String {
+        var result = ""
+        for (language in languages!!) {
+            if (language.fromLabel == label) {
+                result = language.from!!
             }
         }
 
-        return ""
+        return result
     }
 
     private fun setupSpinners() {
@@ -279,15 +286,19 @@ class TranslateActivity : BaseActivity() {
         enableSpinners(true)
     }
 
-    private fun onErrorState() {
+    private fun onTranslationErrorState() {
+        binding.progressBar.visibility = View.GONE
+        enableSpinners(true)
+        showDialog(R.string.translation_error_title, R.string.translation_error_message)
+    }
+
+    private fun onLanguagesErrorState() {
         binding.progressBar.visibility = View.GONE
         enableSpinners(true)
-        showDialog()
+        showDialog(R.string.languages_error_title, R.string.languages_error_message)
     }
 
     companion object {
-        private const val FROM_ID = "from"
-        private const val FROM_LABEL = "fromLabel"
-        private const val TO_LABEL = "toLabel"
+        val TAG = TranslateActivity::class.simpleName
     }
 }

+ 38 - 3
app/src/main/java/com/nextcloud/talk/translate/viewmodels/TranslateViewModel.kt

@@ -6,6 +6,7 @@ import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.ViewModel
 import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.translate.repositories.TranslateRepository
+import com.nextcloud.talk.translate.repositories.model.Language
 import com.nextcloud.talk.users.UserManager
 import com.nextcloud.talk.utils.ApiUtils
 import io.reactivex.Observer
@@ -21,9 +22,14 @@ class TranslateViewModel @Inject constructor(
 
     sealed interface ViewState
 
-    object StartState : ViewState
+    data object StartState : ViewState
     class TranslatedState(val msg: String) : ViewState
-    object ErrorState : ViewState
+
+    class LanguagesRetrievedState(val list: List<Language>) : ViewState
+
+    data object LanguagesErrorState : ViewState
+
+    data object TranslationErrorState : ViewState
 
     private val _viewState: MutableLiveData<ViewState> = MutableLiveData(StartState)
     val viewState: LiveData<ViewState>
@@ -47,6 +53,35 @@ class TranslateViewModel @Inject constructor(
             ?.subscribe(TranslateObserver())
     }
 
+    fun getLanguages() {
+        val currentUser: User = userManager.currentUser.blockingGet()
+        val authorization: String = ApiUtils.getCredentials(currentUser.username, currentUser.token)
+        val url: String = ApiUtils.getUrlForLanguages(currentUser.baseUrl)
+        Log.d(TAG, "URL is: $url")
+        repository.getLanguages(authorization, url)
+            .subscribeOn(Schedulers.io())
+            ?.observeOn(AndroidSchedulers.mainThread())
+            ?.subscribe(object : Observer<List<Language>> {
+                override fun onSubscribe(d: Disposable) {
+                    // unused atm
+                }
+
+                override fun onError(e: Throwable) {
+                    _viewState.value = LanguagesErrorState
+                    Log.e(TAG, "Error while retrieving languages: $e")
+                }
+
+                override fun onComplete() {
+                    // unused atm
+                }
+
+                override fun onNext(list: List<Language>) {
+                    _viewState.value = LanguagesRetrievedState(list)
+                    Log.d(TAG, "Languages retrieved: $list")
+                }
+            })
+    }
+
     inner class TranslateObserver : Observer<String> {
         override fun onSubscribe(d: Disposable) {
             _viewState.value = StartState
@@ -57,7 +92,7 @@ class TranslateViewModel @Inject constructor(
         }
 
         override fun onError(e: Throwable) {
-            _viewState.value = ErrorState
+            _viewState.value = TranslationErrorState
             Log.e(TAG, "Error while translating message", e)
         }
 

+ 1 - 3
app/src/main/java/com/nextcloud/talk/ui/dialog/MessageActionsDialog.kt

@@ -57,7 +57,6 @@ import io.reactivex.Observer
 import io.reactivex.android.schedulers.AndroidSchedulers
 import io.reactivex.disposables.Disposable
 import io.reactivex.schedulers.Schedulers
-import org.json.JSONArray
 import javax.inject.Inject
 
 @AutoInjector(NextcloudTalkApplication::class)
@@ -94,8 +93,7 @@ class MessageActionsDialog(
         initMenuItemTranslate(
             !message.isDeleted &&
                 ChatMessage.MessageType.REGULAR_TEXT_MESSAGE == message.getCalculateMessageType() &&
-                CapabilitiesUtilNew.isTranslationsSupported(user) &&
-                JSONArray((CapabilitiesUtilNew.getLanguages(user) as ArrayList<*>).toArray()).length() > 0
+                CapabilitiesUtilNew.isTranslationsSupported(user)
         )
         initMenuReplyToMessage(message.replyable && hasChatPermission)
         initMenuReplyPrivately(

+ 4 - 0
app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java

@@ -532,6 +532,10 @@ public class ApiUtils {
         return baseUrl + ocsApiVersion + "/translation/translate";
     }
 
+    public static String getUrlForLanguages(String baseUrl) {
+        return baseUrl + ocsApiVersion + "/translation/languages";
+    }
+
     public static String getUrlForReminder(User user, String roomToken, String messageId, int version) {
         String url = ApiUtils.getUrlForChatMessage(version, user.getBaseUrl(), roomToken, messageId);
         return url + "/reminder";

+ 3 - 14
app/src/main/java/com/nextcloud/talk/utils/database/user/CapabilitiesUtilNew.kt

@@ -214,12 +214,8 @@ object CapabilitiesUtilNew {
 
     @JvmStatic
     fun isLinkPreviewAvailable(user: User): Boolean {
-        if (user.capabilities?.coreCapability?.referenceApi != null &&
+        return user.capabilities?.coreCapability?.referenceApi != null &&
             user.capabilities?.coreCapability?.referenceApi == "true"
-        ) {
-            return true
-        }
-        return false
     }
 
     fun isTranslationsSupported(user: User?): Boolean {
@@ -227,20 +223,13 @@ object CapabilitiesUtilNew {
             val capabilities = user.capabilities
             return capabilities?.spreedCapability?.config?.containsKey("chat") == true &&
                 capabilities.spreedCapability!!.config!!["chat"] != null &&
-                capabilities.spreedCapability!!.config!!["chat"]!!.containsKey("translations")
+                capabilities.spreedCapability!!.config!!["chat"]!!.containsKey("has-translation-providers") &&
+                capabilities.spreedCapability!!.config!!["chat"]!!["has-translation-providers"] == true
         }
 
         return false
     }
 
-    fun getLanguages(user: User?): Any? {
-        return if (isTranslationsSupported(user)) {
-            user!!.capabilities!!.spreedCapability!!.config!!["chat"]!!["translations"]
-        } else {
-            null
-        }
-    }
-
     fun isRemindSupported(user: User?): Boolean {
         if (user?.capabilities != null) {
             val capabilities = user.capabilities

+ 2 - 0
app/src/main/res/values/strings.xml

@@ -722,4 +722,6 @@ How to translate with transifex:
     <string name="started_a_call">started a call</string>
     <string name="nc_settings_phone_book_integration_phone_number_dialog_429">Error 429 Too Many Requests</string>
     <string name="nc_caption">Caption</string>
+    <string name="languages_error_title">Retrieval failed</string>
+    <string name="languages_error_message">Languages could not be retrieved</string>
 </resources>