Browse Source

Merge branch 'master' into Snackbar

Signed-off-by: Smarshall <99678760+Smarshal21@users.noreply.github.com>
Smarshall 2 years ago
parent
commit
4121f538c0
42 changed files with 613 additions and 263 deletions
  1. 45 44
      .github/workflows/analysis.yml
  2. 2 2
      .github/workflows/codeql.yml
  3. 7 2
      .github/workflows/pr-feedback.yml
  4. 1 1
      .github/workflows/scorecard.yml
  5. 3 3
      app/build.gradle
  6. 3 5
      app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt
  7. 5 8
      app/src/main/java/com/nextcloud/talk/adapters/items/AdvancedUserItem.java
  8. 4 7
      app/src/main/java/com/nextcloud/talk/adapters/items/ContactItem.java
  9. 7 15
      app/src/main/java/com/nextcloud/talk/adapters/items/MentionAutocompleteItem.java
  10. 3 6
      app/src/main/java/com/nextcloud/talk/adapters/items/ParticipantItem.java
  11. 4 4
      app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingLinkPreviewMessageViewHolder.kt
  12. 10 11
      app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingLocationMessageViewHolder.kt
  13. 2 3
      app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingPollMessageViewHolder.kt
  14. 6 4
      app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingTextMessageViewHolder.kt
  15. 2 3
      app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt
  16. 9 11
      app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingLinkPreviewMessageViewHolder.kt
  17. 14 18
      app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingLocationMessageViewHolder.kt
  18. 7 10
      app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingPollMessageViewHolder.kt
  19. 22 22
      app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingTextMessageViewHolder.kt
  20. 4 8
      app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt
  21. 2 6
      app/src/main/java/com/nextcloud/talk/adapters/messages/PreviewMessageViewHolder.kt
  22. 2 25
      app/src/main/java/com/nextcloud/talk/adapters/messages/Reaction.kt
  23. 2 1
      app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt
  24. 4 8
      app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt
  25. 16 11
      app/src/main/java/com/nextcloud/talk/ui/StatusDrawable.java
  26. 5 3
      app/src/main/java/com/nextcloud/talk/ui/dialog/ChooseAccountDialogFragment.java
  27. 127 2
      app/src/main/java/com/nextcloud/talk/ui/theme/TalkSpecificViewThemeUtils.kt
  28. 1 1
      app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java
  29. 28 8
      app/src/main/java/com/nextcloud/talk/utils/message/MessageUtils.kt
  30. 3 0
      app/src/main/res/values-ca/strings.xml
  31. 1 0
      app/src/main/res/values-da/strings.xml
  32. 9 0
      app/src/main/res/values-es/strings.xml
  33. 220 1
      app/src/main/res/values-fa/strings.xml
  34. 2 2
      app/src/main/res/values-fr/strings.xml
  35. 1 1
      app/src/main/res/values-gl/strings.xml
  36. 5 0
      app/src/main/res/values-ja-rJP/strings.xml
  37. 1 0
      app/src/main/res/values-nb-rNO/strings.xml
  38. 1 0
      app/src/main/res/values-ru/strings.xml
  39. 9 0
      app/src/main/res/values-sr/strings.xml
  40. 5 5
      app/src/main/res/values-uk/strings.xml
  41. 7 0
      app/src/main/res/values-vi/strings.xml
  42. 2 2
      build.gradle

+ 45 - 44
.github/workflows/analysis.yml

@@ -1,53 +1,54 @@
+# synced from @nextcloud/android-config
 name: "Analysis"
 
 on:
-  pull_request:
-    branches: [ master, stable-* ]
-  push:
-    branches: [ master, stable-* ]
+    pull_request:
+        branches: [ "master", "main", "stable-*" ]
+    push:
+        branches: [ "master", "main", "stable-*" ]
 
 permissions:
-  pull-requests: write
-  contents: write
+    pull-requests: write
+    contents: write
 
 concurrency:
-  group: analysis-wrapper-${{ github.head_ref || github.run_id }}
-  cancel-in-progress: true
+    group: analysis-wrapper-${{ github.head_ref || github.run_id }}
+    cancel-in-progress: true
 
 jobs:
-  analysis:
-    runs-on: ubuntu-latest
-    steps:
-      - name: Setup variables
-        id: get-vars
-        run: |
-          if [ -z "$GITHUB_HEAD_REF" ]; then
-              # push
-              echo "branch=$GITHUB_REF_NAME" >> "$GITHUB_OUTPUT"
-              echo "pr=$GITHUB_RUN_ID" >> "$GITHUB_OUTPUT"
-              echo "repo=${{ github.repository }}" >> "$GITHUB_OUTPUT"
-          else
-              # pull request
-              echo "branch=$GITHUB_HEAD_REF" >> "$GITHUB_OUTPUT"
-              echo "pr=${{ github.event.pull_request.number }}" >> "$GITHUB_OUTPUT"
-              echo "repo=${{ github.event.pull_request.head.repo.full_name }}" >> "$GITHUB_OUTPUT"
-          fi
-      - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
-        with:
-          repository: ${{ steps.get-vars.outputs.repo }}
-          ref: ${{ steps.get-vars.outputs.branch }}
-      - name: Set up JDK 17
-        uses: actions/setup-java@cd89f46ac9d01407894225f350157564c9c7cee2 # v3.12.0
-        with:
-          distribution: "temurin"
-          java-version: 17
-      - name: Install dependencies
-        run: |
-          python3 -m pip install defusedxml
-      - name: Run analysis wrapper
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-        run: |
-          mkdir -p $HOME/.gradle
-          echo "org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError" > $HOME/.gradle/gradle.properties
-          scripts/analysis/analysis-wrapper.sh ${{ steps.get-vars.outputs.branch }} ${{ secrets.LOG_USERNAME }} ${{ secrets.LOG_PASSWORD }} $GITHUB_RUN_NUMBER ${{ steps.get-vars.outputs.pr }}
+    analysis:
+        runs-on: ubuntu-latest
+        steps:
+            -   name: Setup variables
+                id: get-vars
+                run: |
+                    if [ -z "$GITHUB_HEAD_REF" ]; then
+                        # push
+                        echo "branch=$GITHUB_REF_NAME" >> "$GITHUB_OUTPUT"
+                        echo "pr=$GITHUB_RUN_ID" >> "$GITHUB_OUTPUT"
+                        echo "repo=${{ github.repository }}" >> "$GITHUB_OUTPUT"
+                    else
+                        # pull request
+                        echo "branch=$GITHUB_HEAD_REF" >> "$GITHUB_OUTPUT"
+                        echo "pr=${{ github.event.pull_request.number }}" >> "$GITHUB_OUTPUT"
+                        echo "repo=${{ github.event.pull_request.head.repo.full_name }}" >> "$GITHUB_OUTPUT"
+                    fi
+            -   uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
+                with:
+                    repository: ${{ steps.get-vars.outputs.repo }}
+                    ref: ${{ steps.get-vars.outputs.branch }}
+            -   name: Set up JDK 17
+                uses: actions/setup-java@cd89f46ac9d01407894225f350157564c9c7cee2 # v3.12.0
+                with:
+                    distribution: "temurin"
+                    java-version: 17
+            -   name: Install dependencies
+                run: |
+                    python3 -m pip install defusedxml
+            -   name: Run analysis wrapper
+                env:
+                    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+                run: |
+                    mkdir -p $HOME/.gradle
+                    echo "org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError" > $HOME/.gradle/gradle.properties
+                    scripts/analysis/analysis-wrapper.sh ${{ steps.get-vars.outputs.branch }} ${{ secrets.LOG_USERNAME }} ${{ secrets.LOG_PASSWORD }} $GITHUB_RUN_NUMBER ${{ steps.get-vars.outputs.pr }}

+ 2 - 2
.github/workflows/codeql.yml

@@ -32,7 +32,7 @@ jobs:
         with:
           swap-size-gb: 10
       - name: Initialize CodeQL
-        uses: github/codeql-action/init@0ba4244466797eb048eb91a6cd43d5c03ca8bd05 # v2.21.2
+        uses: github/codeql-action/init@a09933a12a80f87b87005513f0abb1494c27a716 # v2.21.4
         with:
           languages: ${{ matrix.language }}
       - name: Set up JDK 17
@@ -46,4 +46,4 @@ jobs:
           echo "org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError" > "$HOME/.gradle/gradle.properties"
           ./gradlew assembleDebug
       - name: Perform CodeQL Analysis
-        uses: github/codeql-action/analyze@0ba4244466797eb048eb91a6cd43d5c03ca8bd05 # v2.21.2
+        uses: github/codeql-action/analyze@a09933a12a80f87b87005513f0abb1494c27a716 # v2.21.4

+ 7 - 2
.github/workflows/pr-feedback.yml

@@ -1,3 +1,8 @@
+# This workflow is provided via the organization template repository
+#
+# https://github.com/nextcloud/.github
+# https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
+
 name: 'Ask for feedback on PRs'
 on:
   schedule:
@@ -5,7 +10,7 @@ on:
 
 jobs:
   pr-feedback:
-    runs-on: ubuntu-22.04
+    runs-on: ubuntu-latest
     steps:
       - name: The get-github-handles-from-website action
         uses: marcelklehr/get-github-handles-from-website-action@a739600f6b91da4957f51db0792697afbb2f143c # v1.0.0
@@ -25,5 +30,5 @@ jobs:
             Thank you for contributing to Nextcloud and we hope to hear from you soon!
           days-before-feedback: 14
           start-date: "2023-07-10"
-          exempt-authors: "${{ steps.scrape.outputs.users }}"
+          exempt-authors: "${{ steps.scrape.outputs.users }},nextcloud-command,nextcloud-android-bot"
           exempt-bots: true

+ 1 - 1
.github/workflows/scorecard.yml

@@ -37,6 +37,6 @@ jobs:
 
       # Upload the results to GitHub's code scanning dashboard.
       - name: "Upload to code-scanning"
-        uses: github/codeql-action/upload-sarif@0ba4244466797eb048eb91a6cd43d5c03ca8bd05 # v2.21.2
+        uses: github/codeql-action/upload-sarif@a09933a12a80f87b87005513f0abb1494c27a716 # v2.21.4
         with:
           sarif_file: results.sarif

+ 3 - 3
app/build.gradle

@@ -46,8 +46,8 @@ android {
 
         // mayor.minor.hotfix.increment (for increment: 01-50=Alpha / 51-89=RC / 90-99=stable)
         // xx   .xxx  .xx    .xx
-        versionCode 170100014
-        versionName "17.10.0 Alpha 14"
+        versionCode 170100016
+        versionName "17.10.0 Alpha 16"
 
         flavorDimensions "default"
         renderscriptTargetApi 19
@@ -162,7 +162,7 @@ configurations.all {
 }
 
 dependencies {
-    implementation 'androidx.preference:preference-ktx:1.2.0'
+    implementation 'androidx.preference:preference-ktx:1.2.1'
     detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.23.1")
 	
     implementation fileTree(include: ['*'], dir: 'libs')

+ 3 - 5
app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt

@@ -1083,13 +1083,11 @@ class CallActivity : CallBaseActivity() {
     }
 
     private fun getSpotlightView(): SpotlightView? {
-        val primary = viewThemeUtils.getScheme(binding!!.audioOutputButton.context).primary
-        return SpotlightView.Builder(this)
+        val builder = SpotlightView.Builder(this)
             .introAnimationDuration(300)
             .enableRevealAnimation(true)
             .performClick(false)
             .fadeinTextDuration(400)
-            .headingTvColor(primary)
             .headingTvSize(20)
             .headingTvText(resources.getString(R.string.nc_push_to_talk))
             .subHeadingTvColor(resources.getColor(R.color.bg_default, null))
@@ -1098,11 +1096,11 @@ class CallActivity : CallBaseActivity() {
             .maskColor(Color.parseColor("#dc000000"))
             .target(binding!!.microphoneButton)
             .lineAnimDuration(400)
-            .lineAndArcColor(primary)
             .enableDismissAfterShown(true)
             .dismissOnBackPress(true)
             .usageId("pushToTalk")
-            .show()
+
+        return viewThemeUtils.talk.themeSpotlightView(context, builder).show()
     }
 
     private fun onCameraClick() {

+ 5 - 8
app/src/main/java/com/nextcloud/talk/adapters/items/AdvancedUserItem.java

@@ -41,7 +41,6 @@ import androidx.annotation.Nullable;
 import eu.davidea.flexibleadapter.FlexibleAdapter;
 import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
 import eu.davidea.flexibleadapter.items.IFilterable;
-import eu.davidea.flexibleadapter.utils.FlexibleUtils;
 import eu.davidea.viewholders.FlexibleViewHolder;
 
 public class AdvancedUserItem extends AbstractFlexibleItem<AdvancedUserItem.UserItemViewHolder> implements
@@ -65,8 +64,7 @@ public class AdvancedUserItem extends AbstractFlexibleItem<AdvancedUserItem.User
 
     @Override
     public boolean equals(Object o) {
-        if (o instanceof AdvancedUserItem) {
-            AdvancedUserItem inItem = (AdvancedUserItem) o;
+        if (o instanceof AdvancedUserItem inItem) {
             return participant.equals(inItem.getModel());
         }
         return false;
@@ -107,11 +105,10 @@ public class AdvancedUserItem extends AbstractFlexibleItem<AdvancedUserItem.User
     public void bindViewHolder(FlexibleAdapter adapter, UserItemViewHolder holder, int position, List payloads) {
 
         if (adapter.hasFilter()) {
-            FlexibleUtils.highlightText(
-                    holder.binding.userName,
-                    participant.getDisplayName(),
-                    String.valueOf(adapter.getFilter(String.class)),
-                    viewThemeUtils.getScheme(holder.binding.userName.getContext()).getPrimary());
+            viewThemeUtils.talk.themeAndHighlightText(
+                holder.binding.userName,
+                participant.getDisplayName(),
+                String.valueOf(adapter.getFilter(String.class)));
         } else {
             holder.binding.userName.setText(participant.getDisplayName());
         }

+ 4 - 7
app/src/main/java/com/nextcloud/talk/adapters/items/ContactItem.java

@@ -46,7 +46,6 @@ import eu.davidea.flexibleadapter.FlexibleAdapter;
 import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
 import eu.davidea.flexibleadapter.items.IFilterable;
 import eu.davidea.flexibleadapter.items.ISectionable;
-import eu.davidea.flexibleadapter.utils.FlexibleUtils;
 import eu.davidea.viewholders.FlexibleViewHolder;
 
 public class ContactItem extends AbstractFlexibleItem<ContactItem.ContactItemViewHolder> implements
@@ -74,8 +73,7 @@ public class ContactItem extends AbstractFlexibleItem<ContactItem.ContactItemVie
 
     @Override
     public boolean equals(Object o) {
-        if (o instanceof ContactItem) {
-            ContactItem inItem = (ContactItem) o;
+        if (o instanceof ContactItem inItem) {
             return participant.getCalculatedActorType() == inItem.getModel().getCalculatedActorType() &&
                 participant.getCalculatedActorId().equals(inItem.getModel().getCalculatedActorId());
         }
@@ -135,10 +133,9 @@ public class ContactItem extends AbstractFlexibleItem<ContactItem.ContactItemVie
         holder.binding.nameText.setText(participant.getDisplayName());
 
         if (adapter.hasFilter()) {
-            FlexibleUtils.highlightText(holder.binding.nameText,
-                                        participant.getDisplayName(),
-                                        String.valueOf(adapter.getFilter(String.class)),
-                                        viewThemeUtils.getScheme(holder.binding.nameText.getContext()).getPrimary());
+            viewThemeUtils.talk.themeAndHighlightText(holder.binding.nameText,
+                                                      participant.getDisplayName(),
+                                                      String.valueOf(adapter.getFilter(String.class)));
         }
 
         if (TextUtils.isEmpty(participant.getDisplayName()) &&

+ 7 - 15
app/src/main/java/com/nextcloud/talk/adapters/items/MentionAutocompleteItem.java

@@ -48,7 +48,6 @@ import eu.davidea.flexibleadapter.FlexibleAdapter;
 import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
 import eu.davidea.flexibleadapter.items.IFilterable;
 import eu.davidea.flexibleadapter.items.IFlexible;
-import eu.davidea.flexibleadapter.utils.FlexibleUtils;
 
 public class MentionAutocompleteItem extends AbstractFlexibleItem<ParticipantItem.ParticipantItemViewHolder>
     implements IFilterable<String> {
@@ -103,8 +102,7 @@ public class MentionAutocompleteItem extends AbstractFlexibleItem<ParticipantIte
 
     @Override
     public boolean equals(Object o) {
-        if (o instanceof MentionAutocompleteItem) {
-            MentionAutocompleteItem inItem = (MentionAutocompleteItem) o;
+        if (o instanceof MentionAutocompleteItem inItem) {
             return (objectId.equals(inItem.objectId) && displayName.equals(inItem.displayName));
         }
 
@@ -138,18 +136,12 @@ public class MentionAutocompleteItem extends AbstractFlexibleItem<ParticipantIte
                                      R.color.conversation_item_header,
                                      null));
         if (adapter.hasFilter()) {
-            FlexibleUtils.highlightText(holder.binding.nameText,
-                                        displayName,
-                                        String.valueOf(adapter.getFilter(String.class)),
-                                        viewThemeUtils
-                                            .getScheme(holder.binding.secondaryText.getContext())
-                                            .getPrimary());
-            FlexibleUtils.highlightText(holder.binding.secondaryText,
-                                        "@" + objectId,
-                                        String.valueOf(adapter.getFilter(String.class)),
-                                        viewThemeUtils
-                                            .getScheme(holder.binding.secondaryText.getContext())
-                                            .getPrimary());
+            viewThemeUtils.talk.themeAndHighlightText(holder.binding.nameText,
+                                                      displayName,
+                                                      String.valueOf(adapter.getFilter(String.class)));
+            viewThemeUtils.talk.themeAndHighlightText(holder.binding.secondaryText,
+                                                      "@" + objectId,
+                                                      String.valueOf(adapter.getFilter(String.class)));
         } else {
             holder.binding.nameText.setText(displayName);
             holder.binding.secondaryText.setText("@" + objectId);

+ 3 - 6
app/src/main/java/com/nextcloud/talk/adapters/items/ParticipantItem.java

@@ -51,7 +51,6 @@ import androidx.core.content.res.ResourcesCompat;
 import eu.davidea.flexibleadapter.FlexibleAdapter;
 import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
 import eu.davidea.flexibleadapter.items.IFilterable;
-import eu.davidea.flexibleadapter.utils.FlexibleUtils;
 import eu.davidea.viewholders.FlexibleViewHolder;
 
 public class ParticipantItem extends AbstractFlexibleItem<ParticipantItem.ParticipantItemViewHolder> implements
@@ -81,8 +80,7 @@ public class ParticipantItem extends AbstractFlexibleItem<ParticipantItem.Partic
 
     @Override
     public boolean equals(Object o) {
-        if (o instanceof ParticipantItem) {
-            ParticipantItem inItem = (ParticipantItem) o;
+        if (o instanceof ParticipantItem inItem) {
             return participant.getCalculatedActorType() == inItem.getModel().getCalculatedActorType() &&
                 participant.getCalculatedActorId().equals(inItem.getModel().getCalculatedActorId());
         }
@@ -129,9 +127,8 @@ public class ParticipantItem extends AbstractFlexibleItem<ParticipantItem.Partic
         holder.binding.nameText.setText(participant.getDisplayName());
 
         if (adapter.hasFilter()) {
-            FlexibleUtils.highlightText(holder.binding.nameText, participant.getDisplayName(),
-                                        String.valueOf(adapter.getFilter(String.class)),
-                                        viewThemeUtils.getScheme(holder.binding.nameText.getContext()).getPrimary());
+            viewThemeUtils.talk.themeAndHighlightText(holder.binding.nameText, participant.getDisplayName(),
+                                                      String.valueOf(adapter.getFilter(String.class)));
         }
 
         if (TextUtils.isEmpty(participant.getDisplayName()) &&

+ 4 - 4
app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingLinkPreviewMessageViewHolder.kt

@@ -84,7 +84,8 @@ class IncomingLinkPreviewMessageViewHolder(incomingView: View, payload: Any) :
         var processedMessageText = messageUtils.enrichChatMessageText(
             binding.messageText.context,
             message,
-            binding.messageText.context.resources.getColor(R.color.nc_incoming_text_default)
+            true,
+            viewThemeUtils
         )
 
         processedMessageText = messageUtils.processMessageParameters(
@@ -198,9 +199,8 @@ class IncomingLinkPreviewMessageViewHolder(incomingView: View, payload: Any) :
                 .enrichChatReplyMessageText(
                     binding.messageQuote.quotedMessage.context,
                     parentChatMessage,
-                    binding.messageQuote.quotedMessage.context.resources.getColor(
-                        R.color.nc_incoming_text_default
-                    )
+                    true,
+                    viewThemeUtils
                 )
 
             binding.messageQuote.quotedMessageAuthor

+ 10 - 11
app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingLocationMessageViewHolder.kt

@@ -96,7 +96,7 @@ class IncomingLocationMessageViewHolder(incomingView: View, payload: Any) :
 
         itemView.isSelected = false
 
-        val textSize = context?.resources!!.getDimension(R.dimen.chat_text_size)
+        val textSize = context.resources!!.getDimension(R.dimen.chat_text_size)
         binding.messageText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
         binding.messageText.text = message.text
 
@@ -166,7 +166,7 @@ class IncomingLocationMessageViewHolder(incomingView: View, payload: Any) :
         if (!message.isDeleted && message.parentMessage != null) {
             val parentChatMessage = message.parentMessage
             parentChatMessage!!.activeUser = message.activeUser
-            parentChatMessage!!.imageUrl?.let {
+            parentChatMessage.imageUrl?.let {
                 binding.messageQuote.quotedMessageImage.visibility = View.VISIBLE
                 binding.messageQuote.quotedMessageImage.load(it) {
                     addHeader(
@@ -178,18 +178,17 @@ class IncomingLocationMessageViewHolder(incomingView: View, payload: Any) :
                 binding.messageQuote.quotedMessageImage.visibility = View.GONE
             }
             binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName
-                ?: context!!.getText(R.string.nc_nick_guest)
+                ?: context.getText(R.string.nc_nick_guest)
             binding.messageQuote.quotedMessage.text = messageUtils
                 .enrichChatReplyMessageText(
                     binding.messageQuote.quotedMessage.context,
                     parentChatMessage,
-                    binding.messageQuote.quotedMessage.context.resources.getColor(
-                        R.color.nc_incoming_text_default
-                    )
+                    true,
+                    viewThemeUtils
                 )
 
             binding.messageQuote.quotedMessageAuthor
-                .setTextColor(context!!.resources.getColor(R.color.textColorMaxContrast, null))
+                .setTextColor(context.resources.getColor(R.color.textColorMaxContrast, null))
 
             if (parentChatMessage.actorId?.equals(message.activeUser!!.userId) == true) {
                 viewThemeUtils.platform.colorViewBackground(binding.messageQuote.quoteColoredView)
@@ -217,7 +216,7 @@ class IncomingLocationMessageViewHolder(incomingView: View, payload: Any) :
             }
         }
 
-        binding.webview.settings?.javaScriptEnabled = true
+        binding.webview.settings.javaScriptEnabled = true
 
         binding.webview.webViewClient = object : WebViewClient() {
             @Deprecated("Use shouldOverrideUrlLoading(WebView view, WebResourceRequest request)")
@@ -234,10 +233,10 @@ class IncomingLocationMessageViewHolder(incomingView: View, payload: Any) :
 
         val urlStringBuffer = StringBuffer("file:///android_asset/leafletMapMessagePreview.html")
         urlStringBuffer.append(
-            "?mapProviderUrl=" + URLEncoder.encode(context!!.getString(R.string.osm_tile_server_url))
+            "?mapProviderUrl=" + URLEncoder.encode(context.getString(R.string.osm_tile_server_url))
         )
         urlStringBuffer.append(
-            "&mapProviderAttribution=" + URLEncoder.encode(context!!.getString(R.string.osm_tile_server_attributation))
+            "&mapProviderAttribution=" + URLEncoder.encode(context.getString(R.string.osm_tile_server_attributation))
         )
         urlStringBuffer.append("&locationLat=" + URLEncoder.encode(locationLat))
         urlStringBuffer.append("&locationLon=" + URLEncoder.encode(locationLon))
@@ -262,7 +261,7 @@ class IncomingLocationMessageViewHolder(incomingView: View, payload: Any) :
             val geoLinkWithMarker = addMarkerToGeoLink(locationGeoLink!!)
             val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(geoLinkWithMarker))
             browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
-            context!!.startActivity(browserIntent)
+            context.startActivity(browserIntent)
         } else {
             Snackbar.make(binding.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG).show()
             Log.e(TAG, "locationGeoLink was null or empty")

+ 2 - 3
app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingPollMessageViewHolder.kt

@@ -206,9 +206,8 @@ class IncomingPollMessageViewHolder(incomingView: View, payload: Any) :
                 .enrichChatReplyMessageText(
                     binding.messageQuote.quotedMessage.context,
                     parentChatMessage,
-                    binding.messageQuote.quotedMessage.context.resources.getColor(
-                        R.color.nc_incoming_text_default
-                    )
+                    true,
+                    viewThemeUtils
                 )
 
             binding.messageQuote.quotedMessageAuthor

+ 6 - 4
app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingTextMessageViewHolder.kt

@@ -88,7 +88,8 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) :
         var processedMessageText = messageUtils.enrichChatMessageText(
             binding.messageText.context,
             message,
-            binding.messageText.context.resources.getColor(R.color.nc_incoming_text_default)
+            true,
+            viewThemeUtils
         )
 
         processedMessageText = messageUtils.processMessageParameters(
@@ -197,7 +198,7 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) :
             binding.messageQuote.quotedMessageImage.visibility = View.GONE
         }
         binding.messageQuote.quotedMessageAuthor.text = if (parentChatMessage.actorDisplayName.isNullOrEmpty()) {
-            context!!.getText(R.string.nc_nick_guest)
+            context.getText(R.string.nc_nick_guest)
         } else {
             parentChatMessage.actorDisplayName
         }
@@ -206,7 +207,8 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) :
             .enrichChatReplyMessageText(
                 binding.messageQuote.quotedMessage.context,
                 parentChatMessage,
-                binding.messageQuote.quotedMessage.context.resources.getColor(R.color.nc_incoming_text_default)
+                true,
+                viewThemeUtils
             )
 
         if (parentChatMessage.actorId?.equals(message.activeUser!!.userId) == true) {
@@ -217,7 +219,7 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) :
             )
         }
 
-        binding.messageQuote.quotedChatMessageView.setOnClickListener() {
+        binding.messageQuote.quotedChatMessageView.setOnClickListener {
             val chatActivity = commonMessageInterface as ChatActivity
             chatActivity.jumpToQuotedMessage(parentChatMessage)
         }

+ 2 - 3
app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt

@@ -304,9 +304,8 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) :
                 .enrichChatReplyMessageText(
                     binding.messageQuote.quotedMessage.context,
                     parentChatMessage,
-                    binding.messageQuote.quotedMessage.context.resources.getColor(
-                        R.color.nc_incoming_text_default
-                    )
+                    true,
+                    viewThemeUtils
                 )
 
             binding.messageQuote.quotedMessageAuthor

+ 9 - 11
app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingLinkPreviewMessageViewHolder.kt

@@ -24,11 +24,11 @@ package com.nextcloud.talk.adapters.messages
 
 import android.annotation.SuppressLint
 import android.content.Context
-import android.graphics.PorterDuff
 import android.view.View
 import androidx.appcompat.content.res.AppCompatResources
 import autodagger.AutoInjector
 import coil.load
+import com.nextcloud.android.common.ui.theme.utils.ColorRole
 import com.nextcloud.talk.R
 import com.nextcloud.talk.api.NcApi
 import com.nextcloud.talk.application.NextcloudTalkApplication
@@ -78,12 +78,12 @@ class OutcomingLinkPreviewMessageViewHolder(outcomingView: View, payload: Any) :
         super.onBind(message)
         this.message = message
         sharedApplication!!.componentApplication.inject(this)
-        val textColor = viewThemeUtils.getScheme(binding.messageTime.context).onSurfaceVariant
-        binding.messageTime.setTextColor(textColor)
+        viewThemeUtils.platform.colorTextView(binding.messageTime, ColorRole.ON_SURFACE_VARIANT)
         binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.timestamp)
 
         colorizeMessageBubble(message)
-        var processedMessageText = messageUtils.enrichChatMessageText(binding.messageText.context, message, textColor)
+        var processedMessageText =
+            messageUtils.enrichChatMessageText(binding.messageText.context, message, false, viewThemeUtils)
         processedMessageText = messageUtils.processMessageParameters(
             binding.messageText.context,
             viewThemeUtils,
@@ -106,18 +106,15 @@ class OutcomingLinkPreviewMessageViewHolder(outcomingView: View, payload: Any) :
         }
 
         val readStatusContentDescriptionString = when (message.readStatus) {
-            ReadStatus.READ -> context?.resources?.getString(R.string.nc_message_read)
-            ReadStatus.SENT -> context?.resources?.getString(R.string.nc_message_sent)
+            ReadStatus.READ -> context.resources?.getString(R.string.nc_message_read)
+            ReadStatus.SENT -> context.resources?.getString(R.string.nc_message_sent)
             else -> null
         }
 
         readStatusDrawableInt?.let { drawableInt ->
             AppCompatResources.getDrawable(context, drawableInt)?.let {
                 binding.checkMark.setImageDrawable(it)
-                binding.checkMark.setColorFilter(
-                    viewThemeUtils.getScheme(binding.checkMark.context).onSurfaceVariant,
-                    PorterDuff.Mode.SRC_ATOP
-                )
+                viewThemeUtils.talk.themeMessageCheckMark(binding.checkMark)
             }
         }
 
@@ -176,7 +173,8 @@ class OutcomingLinkPreviewMessageViewHolder(outcomingView: View, payload: Any) :
                 .enrichChatReplyMessageText(
                     binding.messageQuote.quotedMessage.context,
                     parentChatMessage,
-                    viewThemeUtils.getScheme(binding.messageQuote.quotedMessage.context).onSurfaceVariant
+                    false,
+                    viewThemeUtils
                 )
             viewThemeUtils.talk.colorOutgoingQuoteText(binding.messageQuote.quotedMessage)
             viewThemeUtils.talk.colorOutgoingQuoteAuthorText(binding.messageQuote.quotedMessageAuthor)

+ 14 - 18
app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingLocationMessageViewHolder.kt

@@ -25,7 +25,6 @@ package com.nextcloud.talk.adapters.messages
 import android.annotation.SuppressLint
 import android.content.Context
 import android.content.Intent
-import android.graphics.PorterDuff
 import android.net.Uri
 import android.util.Log
 import android.util.TypedValue
@@ -84,15 +83,14 @@ class OutcomingLocationMessageViewHolder(incomingView: View) :
     override fun onBind(message: ChatMessage) {
         super.onBind(message)
         sharedApplication!!.componentApplication.inject(this)
-        val textColor = viewThemeUtils.getScheme(binding.messageTime.context).onSurfaceVariant
-        binding.messageTime.setTextColor(textColor)
+        viewThemeUtils.platform.colorTextView(binding.messageTime, ColorRole.ON_SURFACE_VARIANT)
         binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.timestamp)
 
         realView.isSelected = false
         val layoutParams = binding.messageTime.layoutParams as FlexboxLayout.LayoutParams
         layoutParams.isWrapBefore = false
 
-        val textSize = context!!.resources.getDimension(R.dimen.chat_text_size)
+        val textSize = context.resources.getDimension(R.dimen.chat_text_size)
 
         colorizeMessageBubble(message)
         binding.messageText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
@@ -110,22 +108,19 @@ class OutcomingLocationMessageViewHolder(incomingView: View) :
         }
 
         val readStatusContentDescriptionString = when (message.readStatus) {
-            ReadStatus.READ -> context?.resources?.getString(R.string.nc_message_read)
-            ReadStatus.SENT -> context?.resources?.getString(R.string.nc_message_sent)
+            ReadStatus.READ -> context.resources?.getString(R.string.nc_message_read)
+            ReadStatus.SENT -> context.resources?.getString(R.string.nc_message_sent)
             else -> null
         }
 
         readStatusDrawableInt?.let { drawableInt ->
-            AppCompatResources.getDrawable(context!!, drawableInt)?.let {
+            AppCompatResources.getDrawable(context, drawableInt)?.let {
                 binding.checkMark.setImageDrawable(it)
-                binding.checkMark.setColorFilter(
-                    viewThemeUtils.getScheme(binding.checkMark.context).onSurfaceVariant,
-                    PorterDuff.Mode.SRC_ATOP
-                )
+                viewThemeUtils.talk.themeMessageCheckMark(binding.checkMark)
             }
         }
 
-        binding.checkMark.setContentDescription(readStatusContentDescriptionString)
+        binding.checkMark.contentDescription = readStatusContentDescriptionString
 
         // geo-location
         setLocationDataOnMessageItem(message)
@@ -163,7 +158,7 @@ class OutcomingLocationMessageViewHolder(incomingView: View) :
             }
         }
 
-        binding.webview.settings?.javaScriptEnabled = true
+        binding.webview.settings.javaScriptEnabled = true
 
         binding.webview.webViewClient = object : WebViewClient() {
             @Deprecated("Use shouldOverrideUrlLoading(WebView view, WebResourceRequest request)")
@@ -180,11 +175,11 @@ class OutcomingLocationMessageViewHolder(incomingView: View) :
 
         val urlStringBuffer = StringBuffer("file:///android_asset/leafletMapMessagePreview.html")
         urlStringBuffer.append(
-            "?mapProviderUrl=" + URLEncoder.encode(context!!.getString(R.string.osm_tile_server_url))
+            "?mapProviderUrl=" + URLEncoder.encode(context.getString(R.string.osm_tile_server_url))
         )
         urlStringBuffer.append(
             "&mapProviderAttribution=" + URLEncoder.encode(
-                context!!.getString(
+                context.getString(
                     R.string
                         .osm_tile_server_attributation
                 )
@@ -224,12 +219,13 @@ class OutcomingLocationMessageViewHolder(incomingView: View) :
                 binding.messageQuote.quotedMessageImage.visibility = View.GONE
             }
             binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName
-                ?: context!!.getText(R.string.nc_nick_guest)
+                ?: context.getText(R.string.nc_nick_guest)
             binding.messageQuote.quotedMessage.text = messageUtils
                 .enrichChatReplyMessageText(
                     binding.messageQuote.quotedMessage.context,
                     parentChatMessage,
-                    viewThemeUtils.getScheme(binding.messageQuote.quotedMessage.context).onSurfaceVariant
+                    false,
+                    viewThemeUtils
                 )
             viewThemeUtils.talk.colorOutgoingQuoteText(binding.messageQuote.quotedMessage)
             viewThemeUtils.talk.colorOutgoingQuoteAuthorText(binding.messageQuote.quotedMessageAuthor)
@@ -250,7 +246,7 @@ class OutcomingLocationMessageViewHolder(incomingView: View) :
             val geoLinkWithMarker = addMarkerToGeoLink(locationGeoLink!!)
             val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(geoLinkWithMarker))
             browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
-            context!!.startActivity(browserIntent)
+            context.startActivity(browserIntent)
         } else {
             Snackbar.make(binding.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG).show()
             Log.e(TAG, "locationGeoLink was null or empty")

+ 7 - 10
app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingPollMessageViewHolder.kt

@@ -23,11 +23,11 @@ package com.nextcloud.talk.adapters.messages
 
 import android.annotation.SuppressLint
 import android.content.Context
-import android.graphics.PorterDuff
 import android.view.View
 import androidx.appcompat.content.res.AppCompatResources
 import autodagger.AutoInjector
 import coil.load
+import com.nextcloud.android.common.ui.theme.utils.ColorRole
 import com.nextcloud.talk.R
 import com.nextcloud.talk.api.NcApi
 import com.nextcloud.talk.application.NextcloudTalkApplication
@@ -78,8 +78,7 @@ class OutcomingPollMessageViewHolder(outcomingView: View, payload: Any) :
         super.onBind(message)
         this.message = message
         sharedApplication!!.componentApplication.inject(this)
-        val textColor = viewThemeUtils.getScheme(binding.messageTime.context).onSurfaceVariant
-        binding.messageTime.setTextColor(textColor)
+        viewThemeUtils.platform.colorTextView(binding.messageTime, ColorRole.ON_SURFACE_VARIANT)
         binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.timestamp)
 
         colorizeMessageBubble(message)
@@ -96,18 +95,15 @@ class OutcomingPollMessageViewHolder(outcomingView: View, payload: Any) :
         }
 
         val readStatusContentDescriptionString = when (message.readStatus) {
-            ReadStatus.READ -> context?.resources?.getString(R.string.nc_message_read)
-            ReadStatus.SENT -> context?.resources?.getString(R.string.nc_message_sent)
+            ReadStatus.READ -> context.resources?.getString(R.string.nc_message_read)
+            ReadStatus.SENT -> context.resources?.getString(R.string.nc_message_sent)
             else -> null
         }
 
         readStatusDrawableInt?.let { drawableInt ->
             AppCompatResources.getDrawable(context, drawableInt)?.let {
                 binding.checkMark.setImageDrawable(it)
-                binding.checkMark.setColorFilter(
-                    viewThemeUtils.getScheme(binding.checkMark.context).onSurfaceVariant,
-                    PorterDuff.Mode.SRC_ATOP
-                )
+                viewThemeUtils.talk.themeMessageCheckMark(binding.checkMark)
             }
         }
 
@@ -191,7 +187,8 @@ class OutcomingPollMessageViewHolder(outcomingView: View, payload: Any) :
                 .enrichChatReplyMessageText(
                     binding.messageQuote.quotedMessage.context,
                     parentChatMessage,
-                    viewThemeUtils.getScheme(binding.messageQuote.quotedMessage.context).onSurfaceVariant
+                    false,
+                    viewThemeUtils
                 )
             viewThemeUtils.talk.colorOutgoingQuoteText(binding.messageQuote.quotedMessage)
             viewThemeUtils.talk.colorOutgoingQuoteAuthorText(binding.messageQuote.quotedMessageAuthor)

+ 22 - 22
app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingTextMessageViewHolder.kt

@@ -24,13 +24,13 @@
 package com.nextcloud.talk.adapters.messages
 
 import android.content.Context
-import android.graphics.PorterDuff
 import android.util.TypedValue
 import android.view.View
 import androidx.core.content.res.ResourcesCompat
 import autodagger.AutoInjector
 import coil.load
 import com.google.android.flexbox.FlexboxLayout
+import com.nextcloud.android.common.ui.theme.utils.ColorRole
 import com.nextcloud.talk.R
 import com.nextcloud.talk.application.NextcloudTalkApplication
 import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
@@ -71,11 +71,14 @@ class OutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessageViewH
         realView.isSelected = false
         val layoutParams = binding.messageTime.layoutParams as FlexboxLayout.LayoutParams
         layoutParams.isWrapBefore = false
-        var textSize = context!!.resources.getDimension(R.dimen.chat_text_size)
-        val textColor = viewThemeUtils.getScheme(binding.messageText.context).onSurfaceVariant
-        binding.messageTime.setTextColor(textColor)
-
-        var processedMessageText = messageUtils.enrichChatMessageText(binding.messageText.context, message, textColor)
+        var textSize = context.resources.getDimension(R.dimen.chat_text_size)
+        viewThemeUtils.platform.colorTextView(binding.messageTime, ColorRole.ON_SURFACE_VARIANT)
+        var processedMessageText = messageUtils.enrichChatMessageText(
+            binding.messageText.context,
+            message,
+            false,
+            viewThemeUtils
+        )
         processedMessageText = messageUtils.processMessageParameters(
             binding.messageText.context,
             viewThemeUtils,
@@ -98,7 +101,7 @@ class OutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessageViewH
 
         binding.messageText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
         binding.messageTime.layoutParams = layoutParams
-        binding.messageText.setTextColor(textColor)
+        viewThemeUtils.platform.colorTextView(binding.messageText, ColorRole.ON_SURFACE_VARIANT)
         binding.messageText.text = processedMessageText
 
         binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.timestamp)
@@ -118,22 +121,19 @@ class OutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessageViewH
         }
 
         val readStatusContentDescriptionString = when (message.readStatus) {
-            ReadStatus.READ -> context?.resources?.getString(R.string.nc_message_read)
-            ReadStatus.SENT -> context?.resources?.getString(R.string.nc_message_sent)
+            ReadStatus.READ -> context.resources?.getString(R.string.nc_message_read)
+            ReadStatus.SENT -> context.resources?.getString(R.string.nc_message_sent)
             else -> null
         }
 
         readStatusDrawableInt?.let { drawableInt ->
-            ResourcesCompat.getDrawable(context!!.resources, drawableInt, null)?.let {
+            ResourcesCompat.getDrawable(context.resources, drawableInt, null)?.let {
                 binding.checkMark.setImageDrawable(it)
-                binding.checkMark.setColorFilter(
-                    viewThemeUtils.getScheme(binding.messageText.context).onSurfaceVariant,
-                    PorterDuff.Mode.SRC_ATOP
-                )
+                viewThemeUtils.talk.themeMessageCheckMark(binding.checkMark)
             }
         }
 
-        binding.checkMark.setContentDescription(readStatusContentDescriptionString)
+        binding.checkMark.contentDescription = readStatusContentDescriptionString
 
         itemView.setTag(R.string.replyable_message_view_tag, message.replyable)
 
@@ -158,7 +158,6 @@ class OutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessageViewH
 
     private fun processParentMessage(message: ChatMessage) {
         val parentChatMessage = message.parentMessage
-        val textColor = viewThemeUtils.getScheme(binding.messageQuote.quotedMessage.context).onSurfaceVariant
         parentChatMessage!!.activeUser = message.activeUser
         parentChatMessage.imageUrl?.let {
             binding.messageQuote.quotedMessageImage.visibility = View.VISIBLE
@@ -172,19 +171,20 @@ class OutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessageViewH
             binding.messageQuote.quotedMessageImage.visibility = View.GONE
         }
         binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName
-            ?: context!!.getText(R.string.nc_nick_guest)
+            ?: context.getText(R.string.nc_nick_guest)
         binding.messageQuote.quotedMessage.text = messageUtils
             .enrichChatReplyMessageText(
                 binding.messageQuote.quotedMessage.context,
                 parentChatMessage,
-                textColor
+                false,
+                viewThemeUtils
             )
 
-        binding.messageQuote.quotedMessageAuthor.setTextColor(textColor)
-        binding.messageQuote.quotedMessage.setTextColor(textColor)
-        binding.messageQuote.quoteColoredView.setBackgroundColor(textColor)
+        viewThemeUtils.talk.colorOutgoingQuoteText(binding.messageQuote.quotedMessage)
+        viewThemeUtils.talk.colorOutgoingQuoteAuthorText(binding.messageQuote.quotedMessageAuthor)
+        viewThemeUtils.talk.colorOutgoingQuoteBackground(binding.messageQuote.quoteColoredView)
 
-        binding.messageQuote.quotedChatMessageView.setOnClickListener() {
+        binding.messageQuote.quotedChatMessageView.setOnClickListener {
             val chatActivity = commonMessageInterface as ChatActivity
             chatActivity.jumpToQuotedMessage(parentChatMessage)
         }

+ 4 - 8
app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt

@@ -24,7 +24,6 @@ package com.nextcloud.talk.adapters.messages
 
 import android.annotation.SuppressLint
 import android.content.Context
-import android.graphics.PorterDuff
 import android.os.Handler
 import android.util.Log
 import android.view.View
@@ -86,8 +85,7 @@ class OutcomingVoiceMessageViewHolder(outcomingView: View) :
         super.onBind(message)
         this.message = message
         sharedApplication!!.componentApplication.inject(this)
-        val textColor = viewThemeUtils.getScheme(binding.messageTime.context).onSurfaceVariant
-        binding.messageTime.setTextColor(textColor)
+        viewThemeUtils.platform.colorTextView(binding.messageTime, ColorRole.ON_SURFACE_VARIANT)
         binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.timestamp)
 
         colorizeMessageBubble(message)
@@ -139,10 +137,7 @@ class OutcomingVoiceMessageViewHolder(outcomingView: View) :
         readStatusDrawableInt?.let { drawableInt ->
             AppCompatResources.getDrawable(context!!, drawableInt)?.let {
                 binding.checkMark.setImageDrawable(it)
-                binding.checkMark.setColorFilter(
-                    viewThemeUtils.getScheme(binding.checkMark.context).onSurfaceVariant,
-                    PorterDuff.Mode.SRC_ATOP
-                )
+                viewThemeUtils.talk.themeMessageCheckMark(binding.checkMark)
             }
         }
 
@@ -291,7 +286,8 @@ class OutcomingVoiceMessageViewHolder(outcomingView: View) :
                 .enrichChatReplyMessageText(
                     binding.messageQuote.quotedMessage.context,
                     parentChatMessage,
-                    viewThemeUtils.getScheme(binding.messageQuote.quotedMessage.context).onSurfaceVariant
+                    false,
+                    viewThemeUtils
                 )
             viewThemeUtils.talk.colorOutgoingQuoteText(binding.messageQuote.quotedMessage)
             viewThemeUtils.talk.colorOutgoingQuoteAuthorText(binding.messageQuote.quotedMessageAuthor)

+ 2 - 6
app/src/main/java/com/nextcloud/talk/adapters/messages/PreviewMessageViewHolder.kt

@@ -28,7 +28,6 @@ package com.nextcloud.talk.adapters.messages
 import android.annotation.SuppressLint
 import android.content.Context
 import android.content.Intent
-import android.graphics.PorterDuff
 import android.graphics.drawable.Drawable
 import android.net.Uri
 import android.os.Handler
@@ -235,17 +234,14 @@ abstract class PreviewMessageViewHolder(itemView: View?, payload: Any?) :
         if (message.selectedIndividualHashMap!!.containsKey(KEY_MIMETYPE)) {
             val mimetype = message.selectedIndividualHashMap!![KEY_MIMETYPE]
             val drawableResourceId = getDrawableResourceIdForMimeType(mimetype)
-            val drawable = ContextCompat.getDrawable(context!!, drawableResourceId)
+            var drawable = ContextCompat.getDrawable(context!!, drawableResourceId)
             if (drawable != null &&
                 (
                     drawableResourceId == R.drawable.ic_mimetype_folder ||
                         drawableResourceId == R.drawable.ic_mimetype_package_x_generic
                     )
             ) {
-                drawable.setColorFilter(
-                    viewThemeUtils!!.getScheme(image.context).primary,
-                    PorterDuff.Mode.SRC_ATOP
-                )
+                drawable = viewThemeUtils?.platform?.tintDrawable(context!!, drawable)
             }
             placeholder = drawable
         } else {

+ 2 - 25
app/src/main/java/com/nextcloud/talk/adapters/messages/Reaction.kt

@@ -25,8 +25,6 @@ import android.view.View
 import android.view.ViewGroup
 import android.widget.LinearLayout
 import android.widget.TextView
-import androidx.core.content.ContextCompat
-import com.nextcloud.talk.R
 import com.nextcloud.talk.databinding.ReactionsInsideMessageBinding
 import com.nextcloud.talk.models.json.chat.ChatMessage
 import com.nextcloud.talk.ui.theme.ViewThemeUtils
@@ -65,7 +63,7 @@ class Reaction {
                 val isSelfReaction = message.reactionsSelf != null &&
                     message.reactionsSelf!!.isNotEmpty() &&
                     message.reactionsSelf!!.contains(emoji)
-                val textColor = getTextColor(isOutgoingMessage, isSelfReaction, binding, viewThemeUtils)
+                val textColor = viewThemeUtils.talk.getTextColor(isOutgoingMessage, isSelfReaction, binding)
                 val emojiWithAmountWrapper = getEmojiWithAmountWrapperLayout(
                     binding.reactionsEmojiWrapper.context,
                     emoji,
@@ -112,15 +110,7 @@ class Reaction {
         emojiWithAmountWrapper.layoutParams = layoutInfo.wrapperParams
 
         if (layoutInfo.isSelfReaction) {
-            val color = if (layoutInfo.isOutgoingMessage) {
-                ContextCompat.getColor(
-                    emojiWithAmountWrapper.context,
-                    R.color.bg_message_list_incoming_bubble
-                )
-            } else {
-                layoutInfo.viewThemeUtils.getScheme(emojiWithAmountWrapper.context).primaryContainer
-            }
-            layoutInfo.viewThemeUtils.talk.setCheckedBackground(emojiWithAmountWrapper, color)
+            layoutInfo.viewThemeUtils.talk.setCheckedBackground(emojiWithAmountWrapper, layoutInfo.isOutgoingMessage)
 
             emojiWithAmountWrapper.setPaddingRelative(
                 layoutInfo.paddingSide,
@@ -176,19 +166,6 @@ class Reaction {
         return amountParams
     }
 
-    private fun getTextColor(
-        isOutgoingMessage: Boolean,
-        isSelfReaction: Boolean,
-        binding: ReactionsInsideMessageBinding,
-        viewThemeUtils: ViewThemeUtils
-    ): Int {
-        var textColor = viewThemeUtils.getScheme(binding.root.context).onSurfaceVariant
-        if (!isOutgoingMessage || isSelfReaction) {
-            textColor = ContextCompat.getColor(binding.root.context, R.color.high_emphasis_text)
-        }
-        return textColor
-    }
-
     private data class EmojiWithAmountWrapperLayoutInfo(
         val textColor: Int,
         val amountParams: LinearLayout.LayoutParams,

+ 2 - 1
app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt

@@ -1618,9 +1618,10 @@ class ChatActivity :
                                 currentConversation!!.status,
                                 null,
                                 size,
-                                viewThemeUtils.platform.getScheme(binding.chatToolbar.context).surface,
+                                0,
                                 binding.chatToolbar.context
                             )
+                            viewThemeUtils.talk.themeStatusDrawable(context, status)
                             binding.chatToolbar.findViewById<ImageView>(R.id.chat_toolbar_avatar)
                                 .setImageDrawable(BitmapDrawable(resources, bitmap))
                             binding.chatToolbar.findViewById<ImageView>(R.id.chat_toolbar_status)

+ 4 - 8
app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt

@@ -26,7 +26,6 @@ package com.nextcloud.talk.remotefilebrowser.activities
 
 import android.app.Activity
 import android.content.Intent
-import android.content.res.ColorStateList
 import android.os.Bundle
 import android.util.Log
 import android.view.Menu
@@ -90,13 +89,10 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe
         binding = ActivityRemoteFileBrowserBinding.inflate(layoutInflater)
         setSupportActionBar(binding.remoteFileBrowserItemsToolbar)
         viewThemeUtils.material.themeToolbar(binding.remoteFileBrowserItemsToolbar)
-        val scheme = viewThemeUtils.getScheme(binding.sortListButtonGroup.context)
-        binding.sortListButtonGroup.setBackgroundColor(scheme.surface)
-        binding.sortButton.iconTint = ColorStateList.valueOf(scheme.onSurface)
-        binding.sortButton.setTextColor(scheme.onSurface)
+        viewThemeUtils.talk.themeSortListButtonGroup(binding.sortListButtonGroup)
+        viewThemeUtils.talk.themeSortButton(binding.sortButton)
         viewThemeUtils.material.colorMaterialTextButton(binding.sortButton)
-        binding.pathNavigationBackButton.iconTint = ColorStateList.valueOf(scheme.onSurface)
-        binding.pathNavigationBackButton.setTextColor(scheme.onSurface)
+        viewThemeUtils.talk.themePathNavigationButton(binding.pathNavigationBackButton)
         viewThemeUtils.material.colorMaterialTextButton(binding.pathNavigationBackButton)
         viewThemeUtils.platform.themeStatusBar(this)
         setContentView(binding.root)
@@ -199,7 +195,7 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe
     override fun onCreateOptionsMenu(menu: Menu): Boolean {
         super.onCreateOptionsMenu(menu)
         menuInflater.inflate(R.menu.menu_share_files, menu)
-        filesSelectionDoneMenuItem = menu?.findItem(R.id.files_selection_done)
+        filesSelectionDoneMenuItem = menu.findItem(R.id.files_selection_done)
         return true
     }
 

+ 16 - 11
app/src/main/java/com/nextcloud/talk/ui/StatusDrawable.java

@@ -33,6 +33,7 @@ import android.text.TextUtils;
 
 import com.nextcloud.talk.R;
 
+import androidx.annotation.ColorInt;
 import androidx.annotation.DrawableRes;
 import androidx.annotation.NonNull;
 import androidx.core.content.res.ResourcesCompat;
@@ -44,11 +45,17 @@ public class StatusDrawable extends Drawable {
     private String text;
     private StatusDrawableType icon = StatusDrawableType.UNDEFINED;
     private Paint textPaint;
-    private final int backgroundColor;
+    private int backgroundColor;
     private final float radius;
     private Context context;
 
-    public StatusDrawable(String status, String statusIcon, float statusSize, int backgroundColor, Context context) {
+    public void colorStatusDrawable(@ColorInt int color) {
+        backgroundColor = color;
+        invalidateSelf();
+    }
+
+    public StatusDrawable(String status, String statusIcon, float statusSize, int backgroundColor,
+                          Context context) {
         radius = statusSize;
         this.backgroundColor = backgroundColor;
 
@@ -58,19 +65,17 @@ public class StatusDrawable extends Drawable {
             this.context = context;
         } else if (TextUtils.isEmpty(statusIcon) && status != null) {
             switch (status) {
-                case "online":
+                case "online" -> {
                     icon = StatusDrawableType.ONLINE;
                     this.context = context;
-                    break;
-
-                case "away":
+                }
+                case "away" -> {
                     icon = StatusDrawableType.AWAY;
                     this.context = context;
-                    break;
-
-                default:
-                    // do not show
-                    break;
+                }
+                default -> {
+                }
+                // do not show
             }
         } else {
             text = statusIcon;

+ 5 - 3
app/src/main/java/com/nextcloud/talk/ui/dialog/ChooseAccountDialogFragment.java

@@ -329,12 +329,14 @@ public class ChooseAccountDialogFragment extends DialogFragment {
     private void drawStatus() {
         float size = DisplayUtils.convertDpToPixel(STATUS_SIZE_IN_DP, getContext());
         binding.currentAccount.ticker.setBackground(null);
-        binding.currentAccount.ticker.setImageDrawable(new StatusDrawable(
+        StatusDrawable drawable = new StatusDrawable(
             status.getStatus(),
             status.getIcon(),
             size,
-            viewThemeUtils.getScheme(binding.currentAccount.ticker.getContext()).getSurface(),
-            getContext()));
+            0,
+            getContext());
+        viewThemeUtils.talk.themeStatusDrawable(binding.currentAccount.ticker.getContext(), drawable);
+        binding.currentAccount.ticker.setImageDrawable(drawable);
         binding.currentAccount.ticker.setVisibility(View.VISIBLE);
 
 

+ 127 - 2
app/src/main/java/com/nextcloud/talk/ui/theme/TalkSpecificViewThemeUtils.kt

@@ -26,13 +26,19 @@ import android.content.Context
 import android.content.res.ColorStateList
 import android.graphics.PorterDuff
 import android.graphics.PorterDuffColorFilter
+import android.graphics.Typeface
 import android.graphics.drawable.Drawable
 import android.graphics.drawable.LayerDrawable
 import android.os.Build
+import android.text.Spannable
+import android.text.Spanned
+import android.text.style.ForegroundColorSpan
+import android.text.style.StyleSpan
 import android.view.View
+import android.widget.ImageView
 import android.widget.LinearLayout
+import android.widget.RelativeLayout
 import android.widget.TextView
-import androidx.annotation.ColorInt
 import androidx.annotation.DrawableRes
 import androidx.appcompat.content.res.AppCompatResources
 import androidx.appcompat.widget.SearchView
@@ -42,17 +48,23 @@ import androidx.core.content.res.ResourcesCompat
 import androidx.core.graphics.ColorUtils
 import androidx.core.graphics.drawable.DrawableCompat
 import androidx.core.view.ViewCompat
+import com.google.android.material.button.MaterialButton
 import com.google.android.material.card.MaterialCardView
 import com.google.android.material.materialswitch.MaterialSwitch
 import com.nextcloud.android.common.ui.theme.MaterialSchemes
 import com.nextcloud.android.common.ui.theme.ViewThemeUtilsBase
 import com.nextcloud.android.common.ui.theme.utils.AndroidXViewThemeUtils
 import com.nextcloud.talk.R
+import com.nextcloud.talk.databinding.ReactionsInsideMessageBinding
 import com.nextcloud.talk.ui.MicInputCloud
+import com.nextcloud.talk.ui.StatusDrawable
 import com.nextcloud.talk.ui.WaveformSeekBar
 import com.nextcloud.talk.utils.DisplayUtils
 import com.nextcloud.talk.utils.DrawableUtils
+import com.nextcloud.talk.utils.message.MessageUtils
 import com.vanniktech.emoji.EmojiTextView
+import com.wooplr.spotlight.SpotlightView
+import eu.davidea.flexibleadapter.utils.FlexibleUtils
 import javax.inject.Inject
 import kotlin.math.roundToInt
 
@@ -160,11 +172,19 @@ class TalkSpecificViewThemeUtils @Inject constructor(
         }
     }
 
-    fun setCheckedBackground(linearLayout: LinearLayout, @ColorInt backgroundColor: Int) {
+    fun setCheckedBackground(linearLayout: LinearLayout, incoming: Boolean) {
         withScheme(linearLayout) { scheme ->
             val drawable = AppCompatResources
                 .getDrawable(linearLayout.context, R.drawable.reaction_self_background)!!
                 .mutate()
+            val backgroundColor = if (incoming) {
+                scheme.primaryContainer
+            } else {
+                ContextCompat.getColor(
+                    linearLayout.context,
+                    R.color.bg_message_list_incoming_bubble
+                )
+            }
             DrawableCompat.setTintList(
                 drawable,
                 ColorStateList.valueOf(backgroundColor)
@@ -263,6 +283,111 @@ class TalkSpecificViewThemeUtils @Inject constructor(
         }
     }
 
+    fun themeForegroundColorSpan(context: Context): ForegroundColorSpan {
+        return withScheme(context) { scheme ->
+            return@withScheme ForegroundColorSpan(scheme.primary)
+        }
+    }
+
+    fun themeSpotlightView(context: Context, builder: SpotlightView.Builder): SpotlightView.Builder {
+        return withScheme(context) { scheme ->
+            return@withScheme builder.headingTvColor(scheme.primary).lineAndArcColor(scheme.primary)
+        }
+    }
+
+    fun themeAndHighlightText(
+        textView: TextView,
+        originalText: String?,
+        c: String?
+    ) {
+        withScheme(textView) { scheme ->
+            var constraint = c
+            constraint = FlexibleUtils.toLowerCase(constraint)
+            var start = FlexibleUtils.toLowerCase(originalText).indexOf(constraint)
+            if (start != -1) {
+                val spanText = Spannable.Factory.getInstance().newSpannable(originalText)
+                do {
+                    val end = start + constraint.length
+                    spanText.setSpan(
+                        ForegroundColorSpan(scheme.primary),
+                        start,
+                        end,
+                        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
+                    )
+                    spanText.setSpan(StyleSpan(Typeface.BOLD), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
+                    start = FlexibleUtils.toLowerCase(originalText)
+                        .indexOf(constraint, end + 1) // +1 skips the consecutive span
+                } while (start != -1)
+                textView.setText(spanText, TextView.BufferType.SPANNABLE)
+            } else {
+                textView.setText(originalText, TextView.BufferType.NORMAL)
+            }
+        }
+    }
+
+    fun themeSortButton(sortButton: MaterialButton) {
+        withScheme(sortButton) { scheme ->
+            sortButton.iconTint = ColorStateList.valueOf(scheme.onSurface)
+            sortButton.setTextColor(scheme.onSurface)
+        }
+    }
+
+    fun themePathNavigationButton(navigationBtn: MaterialButton) {
+        withScheme(navigationBtn) { scheme ->
+            navigationBtn.iconTint = ColorStateList.valueOf(scheme.onSurface)
+            navigationBtn.setTextColor(scheme.onSurface)
+        }
+    }
+
+    fun themeSortListButtonGroup(relativeLayout: RelativeLayout) {
+        withScheme(relativeLayout) { scheme ->
+            relativeLayout.setBackgroundColor(scheme.surface)
+        }
+    }
+
+    fun themeStatusDrawable(context: Context, statusDrawable: StatusDrawable) {
+        withScheme(context) { scheme ->
+            statusDrawable.colorStatusDrawable(scheme.surface)
+        }
+    }
+
+    fun themeMessageCheckMark(imageView: ImageView) {
+        withScheme(imageView) { scheme ->
+            imageView.setColorFilter(
+                scheme.onSurfaceVariant,
+                PorterDuff.Mode.SRC_ATOP
+            )
+        }
+    }
+
+    fun themeMarkdown(context: Context, message: String, incoming: Boolean): Spanned {
+        return withScheme(context) { scheme ->
+            return@withScheme if (incoming) {
+                MessageUtils(context).getRenderedMarkdownText(
+                    context,
+                    message,
+                    context.getColor(R.color.nc_incoming_text_default)
+                )
+            } else {
+                MessageUtils(context).getRenderedMarkdownText(context, message, scheme.onSurfaceVariant)
+            }
+        }
+    }
+
+    fun getTextColor(
+        isOutgoingMessage: Boolean,
+        isSelfReaction: Boolean,
+        binding: ReactionsInsideMessageBinding
+    ): Int {
+        return withScheme(binding.root) { scheme ->
+            return@withScheme if (!isOutgoingMessage || isSelfReaction) {
+                ContextCompat.getColor(binding.root.context, R.color.high_emphasis_text)
+            } else {
+                scheme.onSurfaceVariant
+            }
+        }
+    }
+
     companion object {
         private val THEMEABLE_PLACEHOLDER_IDS = listOf(
             R.drawable.ic_mimetype_package_x_generic,

+ 1 - 1
app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java

@@ -292,7 +292,7 @@ public class DisplayUtils {
 
             if (chipXmlRes == R.xml.chip_you) {
                 spannableString.setSpan(
-                    new ForegroundColorSpan(viewThemeUtils.getScheme(context).getOnPrimary()),
+                    viewThemeUtils.talk.themeForegroundColorSpan(context),
                     start,
                     end,
                     Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

+ 28 - 8
app/src/main/java/com/nextcloud/talk/utils/message/MessageUtils.kt

@@ -40,28 +40,48 @@ import io.noties.markwon.ext.tasklist.TaskListDrawable
 import io.noties.markwon.ext.tasklist.TaskListPlugin
 
 class MessageUtils(val context: Context) {
-    fun enrichChatReplyMessageText(context: Context, message: ChatMessage, textColor: Int): Spanned? {
+    fun enrichChatReplyMessageText(
+        context: Context,
+        message: ChatMessage,
+        incoming: Boolean,
+        viewThemeUtils: ViewThemeUtils
+    ): Spanned? {
         return if (message.message == null) {
             null
         } else if (message.renderMarkdown == false) {
-            SpannableString(DisplayUtils.ellipsize(message.message!!, MAX_REPLY_LENGTH))
+            SpannableString(DisplayUtils.ellipsize(message.text, MAX_REPLY_LENGTH))
         } else {
-            enrichChatMessageText(context, DisplayUtils.ellipsize(message.message!!, MAX_REPLY_LENGTH), textColor)
+            enrichChatMessageText(
+                context,
+                DisplayUtils.ellipsize(message.text, MAX_REPLY_LENGTH),
+                incoming,
+                viewThemeUtils
+            )
         }
     }
 
-    fun enrichChatMessageText(context: Context, message: ChatMessage, textColor: Int): Spanned? {
+    fun enrichChatMessageText(
+        context: Context,
+        message: ChatMessage,
+        incoming: Boolean,
+        viewThemeUtils: ViewThemeUtils
+    ): Spanned? {
         return if (message.message == null) {
             null
         } else if (message.renderMarkdown == false) {
             SpannableString(message.message)
         } else {
-            enrichChatMessageText(context, message.message!!, textColor)
+            enrichChatMessageText(context, message.message!!, incoming, viewThemeUtils)
         }
     }
 
-    private fun enrichChatMessageText(context: Context, message: String, textColor: Int): Spanned {
-        return getRenderedMarkdownText(context, message, textColor)
+    private fun enrichChatMessageText(
+        context: Context,
+        message: String,
+        incoming: Boolean,
+        viewThemeUtils: ViewThemeUtils
+    ): Spanned {
+        return viewThemeUtils.talk.themeMarkdown(context, message, incoming)
     }
 
     fun processMessageParameters(
@@ -131,7 +151,7 @@ class MessageUtils(val context: Context) {
         return messageStringInternal
     }
 
-    private fun getRenderedMarkdownText(context: Context, markdown: String, textColor: Int): Spanned {
+    fun getRenderedMarkdownText(context: Context, markdown: String, textColor: Int): Spanned {
         val drawable = TaskListDrawable(textColor, textColor, context.getColor(R.color.bg_default))
         val markwon = Markwon.builder(context).usePlugin(object : AbstractMarkwonPlugin() {
             override fun configureTheme(builder: MarkwonTheme.Builder) {

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

@@ -10,6 +10,7 @@
     <string name="avatar">Avatar</string>
     <string name="away">Absent</string>
     <string name="call_more_actions_dialog_headline">Opcions avançades de trucada</string>
+    <string name="call_running_since_one_hour">La trucada porta una hora en marxa.</string>
     <string name="call_without_notification">Trucada sense notificació</string>
     <string name="camera_permission_granted">S\'ha concedit el permís de càmera. Torneu a triar la càmera.</string>
     <string name="choose_avatar_from_cloud">Trieu un avatar del núvol</string>
@@ -334,6 +335,7 @@
     <string name="nc_settings_theme_key">tema</string>
     <string name="nc_settings_theme_light">Clar</string>
     <string name="nc_settings_theme_title">Tema</string>
+    <string name="nc_settings_typing_status_desc">Comparteix el meu estat d\'escriptura i mostra l\'estat d\'escriptura dels altres</string>
     <string name="nc_settings_use_credentials_title">El proxy necessita credencials</string>
     <string name="nc_settings_warning">Avís</string>
     <string name="nc_settings_wrong_account">Només el compte actual pot ser re-autoritzat</string>
@@ -455,6 +457,7 @@
     <string name="title_attachments">Adjunts</string>
     <string name="today">Avui</string>
     <string name="translate">Traducció</string>
+    <string name="translation_copy_translated_text">Copia el text traduït</string>
     <string name="translation_detect_language">Detectar idioma</string>
     <string name="translation_device_settings">Paràmetres del dispositiu</string>
     <string name="translation_error_message">No s\'ha pogut detectar la llengua</string>

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

@@ -288,6 +288,7 @@
     <string name="today">I dag</string>
     <string name="translate">Oversæt</string>
     <string name="translation_device_settings">Enhedsindstillinger</string>
+    <string name="translation_error_message">Kunne ikke finde sprog</string>
     <string name="translation_from">Fra</string>
     <string name="translation_to">Til</string>
     <string name="unread">Ulæst</string>

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

@@ -10,12 +10,14 @@
     <string name="avatar">Avatar</string>
     <string name="away">Ausente</string>
     <string name="call_more_actions_dialog_headline">Opciones avanzadas de llamada</string>
+    <string name="call_running_since_one_hour">La llamada ha estado activa por una hora.</string>
     <string name="call_without_notification">Llamar sin avisar</string>
     <string name="camera_permission_granted">Los permisos para la cámara fueron otorgados. Por favor seleccione la cámara nuevamente.</string>
     <string name="choose_avatar_from_cloud">Elegir avatar desde la nube</string>
     <string name="clear_status_message">Borrar el mensaje de estado</string>
     <string name="clear_status_message_after">Borrar el mensaje de estado después de</string>
     <string name="close">Cerrar</string>
+    <string name="continuous_voice_message_recording">Bloquear grabación para grabación continua del mensaje de voz</string>
     <string name="conversations">Conversaciones</string>
     <string name="danger_zone">Zona de peligro</string>
     <string name="delete_avatar">Borrar avatar</string>
@@ -63,6 +65,7 @@
     <string name="nc_allow_guests">Permitir invitados</string>
     <string name="nc_attendee_pin">Pin: %1$s</string>
     <string name="nc_biometric_unlock">Desbloquear %1$s</string>
+    <string name="nc_bluetooth_permission_hint">Para habilitar los parlantes bluetooth, por favor, otorgue el permiso \"Dispositivos cercanos\".</string>
     <string name="nc_call_button_content_description_advanced">Opciones avanzadas de llamada</string>
     <string name="nc_call_button_content_description_answer_video_call">Contestar como videollamada</string>
     <string name="nc_call_button_content_description_answer_voice_only">Contestar como llamada de audio solamente</string>
@@ -86,6 +89,7 @@
     <string name="nc_call_unknown">%s llamada</string>
     <string name="nc_call_video">%s videollamada</string>
     <string name="nc_call_voice">%s llamada de voz</string>
+    <string name="nc_camera_permission_hint">Para habilitar la comunicación por vídeo, por favor, otorgue el permiso \"Cámara\".</string>
     <string name="nc_camera_permission_permanently_denied">Para permitir la comunicación de vídeo, concede el permiso de \"Cámara\" en la configuración del sistema.</string>
     <string name="nc_cancel">Cancelar</string>
     <string name="nc_capabilities_failed">Fallo al recuperar capacidades. Abortando.</string>
@@ -207,6 +211,7 @@
     <string name="nc_message_quote_cancel_reply">Cancelar respuesta</string>
     <string name="nc_message_read">Mensajes leídos</string>
     <string name="nc_message_sent">Mensaje enviado</string>
+    <string name="nc_microphone_permission_hint">Para habilitar la comunicación por voz, por favor, otorgue el permiso \"Micrófono\".</string>
     <string name="nc_microphone_permission_permanently_denied">Para permitir la comunicación de voz, concede el permiso de \"Micrófono\" en la configuración del sistema.</string>
     <string name="nc_missed_call">Perdiste una llamada de %s</string>
     <string name="nc_moderator">Moderador</string>
@@ -240,7 +245,11 @@
     <string name="nc_participants">Participantes</string>
     <string name="nc_participants_add">Añadir participantes</string>
     <string name="nc_password">Contraseña</string>
+    <string name="nc_permissions_ask">Establecer permisos</string>
+    <string name="nc_permissions_denied">Algunos permisos fueron denegados.</string>
+    <string name="nc_permissions_rationale_dialog_title">Por favor, otorgue los permisos</string>
     <string name="nc_permissions_settings">Abrir configuración</string>
+    <string name="nc_permissions_settings_hint">Por favor, otorgue los permisos en Ajustes > Permisos</string>
     <string name="nc_phone_book_integration_account_not_found">Cuenta no encontrada</string>
     <string name="nc_phone_book_integration_chat_via">Chat a través de %s</string>
     <string name="nc_pip_microphone_mute">Silenciar micrófono</string>

+ 220 - 1
app/src/main/res/values-fa/strings.xml

@@ -5,30 +5,50 @@
     <string name="audio_output_bluetooth">بلوتوث</string>
     <string name="audio_output_dialog_headline">خروجی صدا</string>
     <string name="audio_output_phone">شماره تلفن</string>
+    <string name="audio_output_speaker">Speaker</string>
+    <string name="audio_output_wired_headset">Wired headset</string>
     <string name="avatar">آواتار</string>
     <string name="away">دور</string>
+    <string name="call_more_actions_dialog_headline">Advanced call options</string>
+    <string name="call_running_since_one_hour">The call has been running for one hour.</string>
+    <string name="call_without_notification">Call without notification</string>
+    <string name="camera_permission_granted">Camera permission granted. Please choose camera again.</string>
+    <string name="choose_avatar_from_cloud">Choose avatar from cloud</string>
     <string name="clear_status_message">پیام وضعیت را پاک کن</string>
     <string name="clear_status_message_after">بعد از آن پیام وضعیت را پاک کن </string>
     <string name="close">بسته</string>
+    <string name="continuous_voice_message_recording">Lock recording for continuously recording of the voice message</string>
     <string name="conversations">گفتگو</string>
+    <string name="danger_zone">Danger Zone</string>
     <string name="delete_avatar">آواتار را پاک کن</string>
     <string name="dnd">مزاحم نشوید</string>
     <string name="dontClear">پاک نکن</string>
     <string name="edit">ویرایش</string>
+    <string name="emoji_backspace">Backspace</string>
     <string name="emoji_category_recent">اخیر</string>
+    <string name="emoji_search">Search emoji</string>
+    <string name="encrypted">Encrypted</string>
+    <string name="error_loading_chats">There was a problem loading your chats</string>
+    <string name="failed_to_save">Failed to save %1$s</string>
     <string name="file_list_folder">پوشه</string>
     <string name="file_list_loading">بارگذاری …</string>
+    <string name="filename_progress">%1$s (%2$d)</string>
     <string name="fourHours">۴ ساعت</string>
     <string name="invisible">نامرئی</string>
     <string name="load_more_results">بار کردن نتیحه‌های بیش‌تر</string>
     <string name="lock_symbol">نماد قفل</string>
+    <string name="lower_hand">Lower hand</string>
+    <string name="mentioned">Mentioned</string>
     <string name="menu_item_sort_by_date_newest_first">تازه‌ترین‌ها اول </string>
     <string name="menu_item_sort_by_date_oldest_first">قدیمی‌ترین‌ها اول </string>
     <string name="menu_item_sort_by_name_a_z">الف تا ی</string>
     <string name="menu_item_sort_by_name_z_a">ی تا الف</string>
     <string name="menu_item_sort_by_size_biggest_first">بزرگترین اول</string>
     <string name="menu_item_sort_by_size_smallest_first">کوچک‌ترین اول</string>
+    <string name="message_poll_tap_to_open">Tap to open poll</string>
     <string name="message_search_begin_empty">جستجو نتیجه‌ای نداشت</string>
+    <string name="message_search_begin_typing">Start typing to search …</string>
+    <string name="message_search_hint">Search …</string>
     <string name="messages">پیام ها</string>
     <string name="nc_Server_account_imported"> حساب  انتخاب‌شده  اکنون  وارد  شده و  در دسترس  است .</string>
     <string name="nc_about">درباره</string>
@@ -43,10 +63,33 @@
     <string name="nc_add_to_favorites">افزودن‌ به مورد علاقه‌ها</string>
     <string name="nc_all_ok_operation">خوب ، همه انجام شد!</string>
     <string name="nc_allow_guests">اجازه میهمانان</string>
+    <string name="nc_attendee_pin">Pin: %1$s</string>
     <string name="nc_biometric_unlock">باز کردن %1$s</string>
+    <string name="nc_bluetooth_permission_hint">To enable bluetooth speakers please grant \"Nearby devices\" permission.</string>
+    <string name="nc_call_button_content_description_advanced">Advanced call options</string>
+    <string name="nc_call_button_content_description_answer_video_call">Answer as video call</string>
+    <string name="nc_call_button_content_description_answer_voice_only">Answer as voice call only</string>
+    <string name="nc_call_button_content_description_audio_output">Change audio output</string>
+    <string name="nc_call_button_content_description_camera">Toggle camera</string>
+    <string name="nc_call_button_content_description_hangup">Hang up</string>
+    <string name="nc_call_button_content_description_microphone">Toggle microphone</string>
+    <string name="nc_call_button_content_description_pip">Open picture-in-picture mode</string>
+    <string name="nc_call_button_content_description_switch_to_self_vide">Switch to self video</string>
+    <string name="nc_call_incoming">INCOMING</string>
     <string name="nc_call_name">نام مکالمه</string>
     <string name="nc_call_name_is_same">نامی که وارد کردید با نام موجود یکسان است</string>
+    <string name="nc_call_notifications">Call notifications</string>
+    <string name="nc_call_raised_hand">%1$s raised the hand</string>
+    <string name="nc_call_reconnecting">Reconnecting …</string>
+    <string name="nc_call_ringing">RINGING</string>
+    <string name="nc_call_state_in_call">%1$s in call</string>
+    <string name="nc_call_state_with_phone">%1$s with phone</string>
+    <string name="nc_call_state_with_video">%1$s with video</string>
     <string name="nc_call_timeout">در  ۴۵ ثانیه پاسخی وجود نداشت ، برای آزمایش دوباره ضربه بزنید</string>
+    <string name="nc_call_unknown">%s call</string>
+    <string name="nc_call_video">%s video call</string>
+    <string name="nc_call_voice">%s voice call</string>
+    <string name="nc_camera_permission_hint">To enable video communication please grant \"Camera\" permission.</string>
     <string name="nc_camera_permission_permanently_denied">برای فعال کردن ارتباطات تصویری ، لطفاً اجازه استفاده از \"دوربین\" را در تنظیمات سیستم قرار دهید.</string>
     <string name="nc_cancel">لغو</string>
     <string name="nc_capabilities_failed">دریافت قابلیت‌ها موفقیت‌آمیز نبود، درحال لغو</string>
@@ -61,12 +104,16 @@
     <string name="nc_clear_history_warning">آیا واقعا می‌خواهید تمام پیام‌ها را در این مکالمه حذف کنید؟</string>
     <string name="nc_client_cert_change">تغییر گواهی مشتری</string>
     <string name="nc_client_cert_setup">گواهی مشتری تنظیم کنید</string>
+    <string name="nc_close_app">Close app</string>
+    <string name="nc_common_and">and</string>
     <string name="nc_common_dismiss">پنهان کن</string>
     <string name="nc_common_error_sorry">متاسفیم؛ خطایی پیش آمد</string>
     <string name="nc_common_set">تنظیم</string>
     <string name="nc_common_skip">پرش</string>
     <string name="nc_configure_cert_auth">گواهی تأیید اعتبار را انتخاب کنید</string>
+    <string name="nc_connecting_call">Connecting …</string>
     <string name="nc_contacts_done">انجام شد</string>
+    <string name="nc_conversation_description">Conversation description</string>
     <string name="nc_conversation_link">پیوند مکالمه</string>
     <string name="nc_conversation_menu_conversation_info">اطلاعات مکالمه</string>
     <string name="nc_conversation_menu_video_call">تماس تصویری</string>
@@ -75,6 +122,7 @@
     <string name="nc_conversations_empty">عضو یک گفتگو شوید یا یک گفتگو جدید شروع کنید</string>
     <string name="nc_conversations_empty_details">به رفقا و هم‌قطاران‌تان سلام کنید!</string>
     <string name="nc_copy_message">کپی کردن</string>
+    <string name="nc_create_poll">Create poll</string>
     <string name="nc_date_header_today">امروز</string>
     <string name="nc_date_header_yesterday">دیروز</string>
     <string name="nc_delete">حذف</string>
@@ -82,19 +130,34 @@
     <string name="nc_delete_call">مکالمه را حذف کنید</string>
     <string name="nc_delete_conversation_more">اگر این مکالمه را حذف کنید ، برای سایر شرکت کنندگان نیز حذف خواهد شد.</string>
     <string name="nc_delete_message">حذف</string>
+    <string name="nc_delete_message_leaked_to_matterbridge">Message deleted successfully, but it might have been leaked to other services</string>
     <string name="nc_demote">تنزل مقام از مدیر</string>
     <string name="nc_description_record_voice">ضبط پیام صوتی</string>
     <string name="nc_description_send_message_button">فرستادن پیام</string>
     <string name="nc_dialog_invalid_password">گذرواژه نادرست</string>
+    <string name="nc_dialog_maintenance_mode">Maintenance mode</string>
+    <string name="nc_dialog_maintenance_mode_description">Server is currently in maintenance mode.</string>
+    <string name="nc_dialog_outdated_client">App is outdated</string>
+    <string name="nc_dialog_outdated_client_description">The app is too old and no longer supported by this server. Please update.</string>
     <string name="nc_dialog_outdated_client_option_update">به‌روز رسانی</string>
+    <string name="nc_dialog_reauth_or_delete">Do you want to reauthorize or delete this account?</string>
     <string name="nc_display_name_not_fetched">امکان دریافت نام وجود ندارد. درحال لغو</string>
     <string name="nc_display_name_not_stored">"امکان ذخیره نام وجود ندارد، درحال لغو "</string>
     <string name="nc_email">رایانامه</string>
+    <string name="nc_expire_message_eight_hours">8 ساعت</string>
+    <string name="nc_expire_message_four_weeks">4 weeks</string>
     <string name="nc_expire_message_off">خاموش</string>
+    <string name="nc_expire_message_one_day">1 روز</string>
     <string name="nc_expire_message_one_hour">۱ ساعت</string>
+    <string name="nc_expire_message_one_week">1 week</string>
+    <string name="nc_expire_messages">Expire chat messages</string>
+    <string name="nc_expire_messages_explanation">Chat messages can be expired after a certain time. Note: Files shared in chat will not be deleted for the owner, but will no longer be shared in the conversation.</string>
     <string name="nc_external_server_failed">" دریافت  تنظیمات سیگنال نا‌موفق بود"</string>
+    <string name="nc_failed_signaling_settings">Target server does not support joining public conversations via mobile phones. You may attempt to join the conversation via web browser.</string>
     <string name="nc_failed_to_perform_operation">با عرض پوزش، مشکلی پیش آمده</string>
     <string name="nc_file_browser_back">بازگشت</string>
+    <string name="nc_file_storage_permission">Permission for file access is required</string>
+    <string name="nc_filter">Filter Conversations</string>
     <string name="nc_following_link"> کاربر  پس از  یک  پیوند  عمومی</string>
     <string name="nc_formatted_message_you">شما: %1$s</string>
     <string name="nc_forward_message">ارسال کردن</string>
@@ -104,40 +167,74 @@
     <string name="nc_group">گروه</string>
     <string name="nc_groups">گروه ها</string>
     <string name="nc_guest">مهمان</string>
+    <string name="nc_guest_access">Guest access</string>
+    <string name="nc_guest_access_allow_failed">Cannot enable/disable guest access.</string>
+    <string name="nc_guest_access_allow_summary">Allow guests to share a public link to join this conversation.</string>
     <string name="nc_guest_access_allow_title">اجازه میهمانان</string>
     <string name="nc_guest_access_password_dialog_hint">یک گذرواژه وارد کنید</string>
+    <string name="nc_guest_access_password_dialog_title">Guest access password</string>
+    <string name="nc_guest_access_password_failed">Error during setting/disabling the password.</string>
+    <string name="nc_guest_access_password_summary">Set a password to restrict who can use the public link.</string>
     <string name="nc_guest_access_password_title">محافظت از رمز عبور</string>
     <string name="nc_guest_access_password_weak_alert_title">رمز عبور ضعیف</string>
+    <string name="nc_guest_access_resend_invitations">Resend invitations</string>
+    <string name="nc_guest_access_resend_invitations_failed">Invitations were not send due to an error.</string>
+    <string name="nc_guest_access_resend_invitations_successful">Invitations were sent out again.</string>
+    <string name="nc_guest_access_share_link">Share conversation link</string>
+    <string name="nc_hint_enter_a_message">Enter a message …</string>
     <string name="nc_important_conversation">گفتگوی مهم</string>
+    <string name="nc_important_conversation_desc">Notifications in this conversation will override Do Not Disturb settings</string>
     <string name="nc_join_via_link">با یک پیوند ملحق شوید</string>
     <string name="nc_join_via_web">از طریق وب ملحق شوید</string>
     <string name="nc_last_moderator">قبل از ترک ، باید یک مدیر جدید را تعیین کنید %1$s.</string>
     <string name="nc_last_moderator_title">نمی توان مکالمه را ترک کرد</string>
     <string name="nc_last_modified">تغییرات %1$s |  آخرین تغییرات: %2$s</string>
     <string name="nc_leave">ترک صحبت</string>
+    <string name="nc_leaving_call">Leaving call …</string>
     <string name="nc_license_summary">مجوز عمومی عمومی گنو ، نسخه 3</string>
     <string name="nc_license_title">مجوز</string>
     <string name="nc_limit_hit">%sحد کاراکترها زده شده است</string>
+    <string name="nc_list_open_conversations">List open conversations</string>
     <string name="nc_lobby">لابی</string>
+    <string name="nc_lobby_start_date">This meeting is scheduled for %1$s</string>
+    <string name="nc_lobby_start_soon">The meeting will start soon</string>
     <string name="nc_lobby_waiting">شما در حال حاضر در لابی منتظر هستید.</string>
+    <string name="nc_location_current_position_description">Your current location</string>
+    <string name="nc_location_permission_required">location permission is required</string>
+    <string name="nc_location_unknown">Position unknown</string>
+    <string name="nc_locked">Locked</string>
     <string name="nc_locked_tap_to_unlock">برای باز کردن قفل ضربه بزنید</string>
     <string name="nc_manual">تنظیم نشده</string>
     <string name="nc_mark_as_read">علامت به عنوان خوانده‌شده</string>
     <string name="nc_mark_as_unread">علامت به عنوان خوانده‌نشده</string>
+    <string name="nc_message_failed_to_send">Failed to send message:</string>
     <string name="nc_message_quote_cancel_reply">لغو پاسخ</string>
+    <string name="nc_message_read">Message read</string>
     <string name="nc_message_sent">پیام ارسال شد</string>
+    <string name="nc_microphone_permission_hint">To enable voice communication please grant \"Microphone\" permission.</string>
     <string name="nc_microphone_permission_permanently_denied">برای فعال کردن ارتباط صوتی ، لطفاً در \"تنظیمات سیستم\" اجازه استفاه از \"میکروفون\" را قرار دهید.</string>
+    <string name="nc_missed_call">You missed a call from %s</string>
     <string name="nc_moderator">مدیر</string>
     <string name="nc_never">هرگز ملحق نشوید</string>
     <string name="nc_new_conversation">مکالمه جدید</string>
+    <string name="nc_new_mention">Unread mentions</string>
     <string name="nc_new_messages">پیام‌های خوانده نشده</string>
     <string name="nc_new_password">گذرواژه جدید</string>
+    <string name="nc_nextcloud_talk_app_not_installed">%1$s not available (not installed or restricted by admin)</string>
     <string name="nc_nick_guest">مهمان</string>
     <string name="nc_no">نه</string>
+    <string name="nc_no_open_conversations_headline">No open conversations</string>
+    <string name="nc_no_open_conversations_text">No open conversations that you can join.\nEither there are no open conversations or you already joined all of them.</string>
     <string name="nc_no_proxy">پروکسی نیست</string>
+    <string name="nc_not_allowed_to_activate_audio">You are not allowed to activate audio!</string>
+    <string name="nc_not_allowed_to_activate_video">You are not allowed to activate video!</string>
     <string name="nc_notification_channel">کانال اعلان %1$s روی %2$s</string>
+    <string name="nc_notification_channel_calls">Calls</string>
+    <string name="nc_notification_channel_calls_description">Notify about incoming calls</string>
     <string name="nc_notification_channel_messages">پیام ها</string>
+    <string name="nc_notification_channel_messages_description">Notify about incoming messages</string>
     <string name="nc_notification_channel_uploads">آپلودها</string>
+    <string name="nc_notification_channel_uploads_description">Notify about upload progress</string>
     <string name="nc_notification_settings">تنظیمات اعلان</string>
     <string name="nc_notify_me_always">همیشه اعلان شود</string>
     <string name="nc_notify_me_mention">وقتی ذکر شد اطلاع دهید</string>
@@ -148,7 +245,15 @@
     <string name="nc_participants">شركت كنندگان</string>
     <string name="nc_participants_add">افزودن عضو</string>
     <string name="nc_password">گذرواژه</string>
+    <string name="nc_permissions_ask">Set permissions</string>
+    <string name="nc_permissions_denied">Some permissions were denied.</string>
+    <string name="nc_permissions_rationale_dialog_title">Please allow permissions</string>
     <string name="nc_permissions_settings">تنظیمات را باز کنید</string>
+    <string name="nc_permissions_settings_hint">Please grant permissions at Settings > Permissions</string>
+    <string name="nc_phone_book_integration_account_not_found">Account not found</string>
+    <string name="nc_phone_book_integration_chat_via">Chat via %s</string>
+    <string name="nc_pip_microphone_mute">Mute microphone</string>
+    <string name="nc_pip_microphone_unmute">Enable microphone</string>
     <string name="nc_plain_old_messages">پیام ها</string>
     <string name="nc_privacy">حریم خصوصی</string>
     <string name="nc_proceed">ادامه</string>
@@ -159,10 +264,14 @@
     <string name="nc_push_disabled">دریافت اعلانات غیرفعال است</string>
     <string name="nc_push_to_talk">برای صحبت کردن فشار دهید</string>
     <string name="nc_push_to_talk_desc">با غیر فعال کردن میکروفن، برای استفاده از Push-to-talk کلیک &amp; نگه‌داشتن را انجام دهید</string>
+    <string name="nc_remote_audio_off">Remote audio off</string>
+    <string name="nc_remove_circle_and_members">Remove circle and members</string>
     <string name="nc_remove_from_favorites">حذف کردن از مورد علاقه‌ها</string>
+    <string name="nc_remove_group_and_members">Remove group and members</string>
     <string name="nc_remove_participant">شرکت کننده را حذف کنید</string>
     <string name="nc_rename">تغییر نام مکالمه</string>
     <string name="nc_reply">پاسخ</string>
+    <string name="nc_reply_privately">Reply privately</string>
     <string name="nc_screen_lock_timeout_30">۳۰ ثانیه</string>
     <string name="nc_screen_lock_timeout_300">۵ دقیقه</string>
     <string name="nc_screen_lock_timeout_60">۱ دقیقه</string>
@@ -173,6 +282,7 @@
     <string name="nc_screen_lock_timeout_three_hundred">۳۰۰</string>
     <string name="nc_search">جستجو</string>
     <string name="nc_select_an_account">یک حساب کاربری انتخاب کنید</string>
+    <string name="nc_select_participants">Select participants</string>
     <string name="nc_sent_a_gif" formatted="true">ارسال یک GIF %1$s.</string>
     <string name="nc_sent_a_gif_you">شما یک GIF ارسال کردید.</string>
     <string name="nc_sent_a_video" formatted="true">ارسال یک فایل ویدئو %1$s.</string>
@@ -183,6 +293,12 @@
     <string name="nc_sent_an_audio_you">شما صوتی ارسال کردید.</string>
     <string name="nc_sent_an_image" formatted="true">ارسال یک تصویر %1$s.</string>
     <string name="nc_sent_an_image_you">شما یک تصویر ارسال کردید</string>
+    <string name="nc_sent_location" formatted="true">%1$s sent a location.</string>
+    <string name="nc_sent_location_you">You sent a location.</string>
+    <string name="nc_sent_poll" formatted="true">%1$s sent a poll.</string>
+    <string name="nc_sent_poll_you">You sent a poll.</string>
+    <string name="nc_sent_voice" formatted="true">%1$s sent a voice message.</string>
+    <string name="nc_sent_voice_you">You sent a voice message.</string>
     <string name="nc_server_connect">آزمایش اتصال به سرور</string>
     <string name="nc_server_db_upgrade_needed">لطفا پایگاه داده %1$s خود را ارتقا دهید</string>
     <string name="nc_server_failed_to_import_account">" وارد کردن  حساب  انتخاب‌شده موفقیت آمیز نبود"</string>
@@ -201,6 +317,7 @@
     <string name="nc_settings_account_updated">به جای اضافه کردن حساب جدید، حساب از قبل موجود شما بروز شد</string>
     <string name="nc_settings_advanced_title">پیشرفته</string>
     <string name="nc_settings_appearance">ظاهر</string>
+    <string name="nc_settings_call_ringtone">Calls</string>
     <string name="nc_settings_incognito_keyboard_desc">دستورالعمل صفحه کلید را برای غیرفعال کردن یادگیری شخصی (بدون ضمانت)</string>
     <string name="nc_settings_incognito_keyboard_title">صفحه کلید ناشناس</string>
     <string name="nc_settings_no_ringtone">بدون صدا</string>
@@ -208,11 +325,21 @@
     <string name="nc_settings_notification_sounds">صدا</string>
     <string name="nc_settings_notification_sounds_post_oreo">آگاهی‌ها</string>
     <string name="nc_settings_other_notifications_ringtone">پیام ها</string>
+    <string name="nc_settings_phone_book_integration_desc">Match contacts based on phone number to integrate Talk shortcut into system contacts app</string>
+    <string name="nc_settings_phone_book_integration_phone_number_dialog_description">You can set your phone number so other users will be able to find you</string>
+    <string name="nc_settings_phone_book_integration_phone_number_dialog_invalid">Invalid phone number</string>
+    <string name="nc_settings_phone_book_integration_phone_number_dialog_success">Phone number set successfully</string>
     <string name="nc_settings_phone_book_integration_phone_number_dialog_title">شماره تلفن</string>
+    <string name="nc_settings_phone_book_integration_title">Phone number integration</string>
     <string name="nc_settings_privacy">حریم خصوصی</string>
     <string name="nc_settings_proxy_host_title">میزبان پروکسی</string>
+    <string name="nc_settings_proxy_password_title">Proxy password</string>
     <string name="nc_settings_proxy_port_title">پورت پروکسی</string>
     <string name="nc_settings_proxy_type_title">نوع پروکسی</string>
+    <string name="nc_settings_proxy_username_title">Proxy username</string>
+    <string name="nc_settings_read_privacy_desc">Share my read-status and show the read-status of others</string>
+    <string name="nc_settings_read_privacy_title">Read status</string>
+    <string name="nc_settings_reauthorize">Reauthorize account</string>
     <string name="nc_settings_remove">حذف</string>
     <string name="nc_settings_remove_account">حذف حساب کاربری</string>
     <string name="nc_settings_remove_confirmation">لطفاً قصد خود را برای حذف حساب جاری تأیید کنید.</string>
@@ -221,39 +348,96 @@
     <string name="nc_settings_screen_lock_title">قفل صفحه</string>
     <string name="nc_settings_screen_security_desc">از گرفتن عکسهای صفحه در لیست اخیر و داخل برنامه جلوگیری می کند</string>
     <string name="nc_settings_screen_security_title">امنیت صفحه نمایش</string>
+    <string name="nc_settings_server_almost_eol">The server version is very old and will not be supported in the next release!</string>
+    <string name="nc_settings_server_eol">The server version is too old and not supported by this version of the Android app</string>
+    <string name="nc_settings_server_eol_title">Unsupported server</string>
     <string name="nc_settings_theme_battery_saver">تنظیم شده توسط ذخیره نیرو</string>
     <string name="nc_settings_theme_dark">تیره</string>
     <string name="nc_settings_theme_follow_system">از پیش‌فرض سیستم استفاده کنید</string>
     <string name="nc_settings_theme_key">تم</string>
     <string name="nc_settings_theme_light">روشن</string>
     <string name="nc_settings_theme_title">تم</string>
+    <string name="nc_settings_typing_status_desc">Share my typing-status and show the typing-status of others</string>
+    <string name="nc_settings_typing_status_hpb_description">Typing status is only available when using a high performance backend (HPB)</string>
+    <string name="nc_settings_typing_status_title">Typing status</string>
+    <string name="nc_settings_use_credentials_title">Proxy requires credentials</string>
     <string name="nc_settings_warning">هشدار</string>
     <string name="nc_settings_wrong_account">فقط حساب کاربری فعلی قابل گرفتن مجوز مجدد است</string>
+    <string name="nc_share_contact">Share contact</string>
+    <string name="nc_share_contact_permission">Permission to read contacts is required</string>
+    <string name="nc_share_current_location">Share current location</string>
+    <string name="nc_share_location">Share location</string>
     <string name="nc_share_subject">دعوت %1$s</string>
     <string name="nc_share_text">به مکالمه %1$s/index.php/call/%2$s ملحق شوید</string>
     <string name="nc_share_text_pass">رمز عبور: %1$s</string>
     <string name="nc_share_this_location">اشتراک این مکان</string>
     <string name="nc_share_to_choose_account">حساب کاربری را انتخاب کنید</string>
+    <string name="nc_shared_items">Shared items</string>
     <string name="nc_shared_items_deck_card">کارت deck</string>
+    <string name="nc_shared_items_description">Images, files, voice messages …</string>
+    <string name="nc_shared_items_empty">No shared items</string>
     <string name="nc_shared_items_location">محل</string>
+    <string name="nc_shared_location">Shared location</string>
     <string name="nc_sort_by">مرتب‌سازی بر اساس</string>
     <string name="nc_start_time">زمان شروع</string>
     <string name="nc_switch_account">تعویض حساب</string>
+    <string name="nc_upload_choose_local_files">Choose files</string>
+    <string name="nc_upload_confirm_send_multiple">Send these files to %1$s?</string>
+    <string name="nc_upload_confirm_send_single">Send this file to %1$s?</string>
+    <string name="nc_upload_failed">Sorry, upload failed</string>
+    <string name="nc_upload_failed_notification_text">Failed to upload %1$s</string>
+    <string name="nc_upload_failed_notification_title">Failure</string>
+    <string name="nc_upload_from_cloud">Share from %1$s</string>
+    <string name="nc_upload_from_device">Upload from device</string>
     <string name="nc_upload_in_progess">در حال آپلود</string>
+    <string name="nc_upload_notification_text">%1$s to %2$s - %3$s\%%</string>
     <string name="nc_upload_picture_from_cam">عکس گرفتن</string>
+    <string name="nc_upload_video_from_cam">Take video</string>
     <string name="nc_user">کاربر</string>
+    <string name="nc_video_filename">Video recording from %1$s</string>
+    <string name="nc_voice_message_filename">Talk recording from %1$s (%2$s)</string>
+    <string name="nc_voice_message_hold_to_record_info">Hold to record, release to send.</string>
+    <string name="nc_voice_message_missing_audio_permission">Permission for audio recording is required</string>
+    <string name="nc_voice_message_slide_to_cancel">« Slide to cancel</string>
     <string name="nc_webinar">وبینار</string>
     <string name="nc_wrong_link">پیوند مکالمه معتبر نیست</string>
     <string name="nc_wrong_password">کلمه عبور اشتباه</string>
     <string name="nc_yes">بله</string>
+    <string name="no_phone_book_integration_due_to_permissions">No phone number integration due to missing permissions</string>
     <string name="oneHour">۱ ساعت</string>
     <string name="online">آنلاین</string>
     <string name="online_status">وضعیت آنلاین</string>
     <string name="openConversations">مکالمه جدید</string>
+    <string name="open_in_files_app">Open in Files app</string>
+    <string name="play_pause_voice_message">Play/pause voice message</string>
+    <string name="polls_add_option">Add option</string>
+    <string name="polls_edit_vote">Edit vote</string>
+    <string name="polls_end_poll">End poll</string>
+    <string name="polls_end_poll_confirm">Do you really want to end this poll? This cannot be undone.</string>
+    <string name="polls_max_votes_reached">You cannot vote with more options for this poll.</string>
+    <string name="polls_multiple_answers">Multiple answers</string>
+    <string name="polls_option_delete">Delete option %1$s</string>
+    <string name="polls_option_hint">Option %1$s</string>
     <string name="polls_options">گزینه‌ها</string>
+    <string name="polls_private_poll">Private poll</string>
+    <string name="polls_question">Question</string>
+    <string name="polls_question_hint">Your question</string>
     <string name="polls_results_subtitle">نتایج</string>
     <string name="polls_settings">تنظیمات</string>
+    <string name="polls_submit_vote">Vote</string>
+    <string name="polls_voted_hidden_success">Vote submitted</string>
+    <string name="raise_hand">Raise hand</string>
     <string name="reactions_tab_all">همه</string>
+    <string name="read_storage_no_permission">Sharing files from storage is not possible without permissions</string>
+    <string name="record_active_info">The call is being recorded</string>
+    <string name="record_cancel_start">Cancel recording start</string>
+    <string name="record_failed_info">The recording failed. Please contact your administrator.</string>
+    <string name="record_start_description">Start recording</string>
+    <string name="record_stop_confirm_message">Do you really want to stop the recording?</string>
+    <string name="record_stop_confirm_title">Stop Call recording</string>
+    <string name="record_stop_description">Stop recording</string>
+    <string name="record_stopping">Stopping recording …</string>
+    <string name="restrict_join_other_room_while_call">It\'s not possible to join other rooms while being in a call</string>
     <string name="save">ذخیره</string>
     <string name="scope_federated_description">فقط با سرورهای قابل اعتماد همگام سازی شود</string>
     <string name="scope_federated_title">فدرال</string>
@@ -263,8 +447,16 @@
     <string name="scope_private_title">خصوصی</string>
     <string name="scope_published_description">با سرورهای قابل اعتماد و دفترچه آدرس عمومی و همگانی همگام سازی شود</string>
     <string name="scope_published_title">منتشر شده</string>
+    <string name="scope_toggle">Scope toggle</string>
+    <string name="scope_toggle_description">Change privacy level of %1$s</string>
+    <string name="scroll_to_bottom">Scroll to bottom</string>
     <string name="secondsAgo">یک ثانیه پیش</string>
     <string name="selected_list_item">انتخاب شد</string>
+    <string name="send_to">Send to</string>
+    <string name="send_to_forbidden">You are not allowed to share content to this chat</string>
+    <string name="send_to_three_dots">Send to …</string>
+    <string name="send_without_notification">Send without notification</string>
+    <string name="set_avatar_from_camera">Set avatar from camera</string>
     <string name="set_status">تنظیم وضعیت</string>
     <string name="set_status_message">تنظیم پیام وضعیت</string>
     <string name="share">هم‌رسانی</string>
@@ -272,21 +464,43 @@
     <string name="shared_items_file">فایل</string>
     <string name="shared_items_media">رسانه‌ها</string>
     <string name="shared_items_other">اعلان‌ها</string>
+    <string name="shared_items_poll">Poll</string>
+    <string name="shared_items_recording">Call recording</string>
     <string name="shared_items_voice">صدا</string>
     <string name="starred">مورد‌ ‌علاقه‌</string>
+    <string name="startCallForbidden">You are not allowed to start a call</string>
     <string name="status_message">پیغام وضعیت</string>
+    <string name="switch_to_breakout_room">Switch to breakout room</string>
+    <string name="switch_to_main_room">Switch to main room</string>
     <string name="take_photo">عکس گرفتن</string>
+    <string name="take_photo_error_deleting_picture">Error taking picture</string>
+    <string name="take_photo_permission">Taking a photo is not possible without permissions</string>
+    <string name="take_photo_retake_photo">Re-take photo</string>
     <string name="take_photo_send">ارسال</string>
     <string name="take_photo_switch_camera">دوربین را عوض کنید</string>
+    <string name="take_photo_toggle_crop">Crop photo</string>
+    <string name="take_photo_toggle_lowres">Reduce image size</string>
     <string name="take_photo_toggle_torch">تغییر مشعل</string>
     <string name="thirtyMinutes">۳۰ دقیقه</string>
     <string name="thisWeek">این هفته</string>
+    <string name="this_is_a_test_message">This is a test message</string>
     <string name="title_attachments">پیوست ها</string>
     <string name="today">امروز</string>
     <string name="translate">ترجمه</string>
+    <string name="translation">Translation</string>
+    <string name="translation_copy_translated_text">Copy translated text</string>
+    <string name="translation_detect_language">Detect language</string>
     <string name="translation_device_settings">تنظیمات افزاره</string>
+    <string name="translation_error_message">Could not detect language</string>
+    <string name="translation_error_title">Translation failed</string>
     <string name="translation_from">از</string>
     <string name="translation_to">به</string>
+    <string name="typing_1_other">and 1 other is typing …</string>
+    <string name="typing_are_typing">are typing …</string>
+    <string name="typing_is_typing">is typing …</string>
+    <string name="typing_x_others">and %1$s others are typing …</string>
+    <string name="unread">Unread</string>
+    <string name="upload_new_avatar_from_device">Upload new avatar from device</string>
     <string name="user_info_address">نشانی</string>
     <string name="user_info_displayname">نام کامل</string>
     <string name="user_info_email">رایانامه</string>
@@ -294,7 +508,12 @@
     <string name="user_info_twitter">توییتر</string>
     <string name="user_info_website">وب‌ سایت</string>
     <string name="user_status">وضعیت</string>
+    <string name="userinfo_error_text">Failed to retrieve personal user information.</string>
     <string name="userinfo_no_info_headline">اطلاعات شخصی تنطیم نشده</string>
     <string name="userinfo_no_info_text">نام، تصویر و اطلاعات تماس را در صفحه نمایه خود اضافه کنید.</string>
     <string name="whats_your_status">وضعیت شما چیست؟</string>
-    </resources>
+    <plurals name="polls_amount_voters">
+        <item quantity="one">%d vote</item>
+        <item quantity="other">%d votes</item>
+    </plurals>
+</resources>

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

@@ -249,7 +249,7 @@
     <string name="nc_privacy">Vie privée</string>
     <string name="nc_proceed">Continuer</string>
     <string name="nc_profile_personal_info_title">Informations personnelles</string>
-    <string name="nc_promote">Promouvoir en modérateur</string>
+    <string name="nc_promote">Promouvoir comme modérateur</string>
     <string name="nc_public_call">Nouvelle conversation publique</string>
     <string name="nc_public_call_explanation">Les conversations publiques vous permettent d\'inviter des personnes extérieures grâce à un lien spécialement créé.</string>
     <string name="nc_push_disabled">Notifications push désactivées</string>
@@ -332,7 +332,7 @@
     <string name="nc_settings_read_privacy_title">Statut de lecture</string>
     <string name="nc_settings_reauthorize">Ré-autoriser le compte</string>
     <string name="nc_settings_remove">Effacer</string>
-    <string name="nc_settings_remove_account">Supprimer le compte</string>
+    <string name="nc_settings_remove_account">Retirer le compte</string>
     <string name="nc_settings_remove_confirmation">Veuillez confirmer votre volonté de supprimer le compte actuel.</string>
     <string name="nc_settings_screen_lock_desc">Verrouiller %1$s avec le verrouillage d’écran Android ou une méthode biométrique supportée</string>
     <string name="nc_settings_screen_lock_timeout_title">Délai d\'inactivité avant verrouillage de l\'écran</string>

+ 1 - 1
app/src/main/res/values-gl/strings.xml

@@ -151,7 +151,7 @@
     <string name="nc_expire_message_one_hour">1 hora</string>
     <string name="nc_expire_message_one_week">1 semana</string>
     <string name="nc_expire_messages">Caducidade das mensaxes das parolas</string>
-    <string name="nc_expire_messages_explanation">As mensaxes das parolas poden caducar após dun tempo determinado. Nota: os ficheiros compartidos na parola non se eliminarán para o propietario, mais xa non se compartirán na conversa.</string>
+    <string name="nc_expire_messages_explanation">As mensaxes das parolas poden caducar após dun tempo determinado. Nota: Os ficheiros compartidos na parola non se eliminarán para o propietario, mais xa non se compartirán na conversa.</string>
     <string name="nc_external_server_failed">Produciuse un fallo ao recuperar os axustes da sinalización</string>
     <string name="nc_failed_signaling_settings">O servidor de destino non admite unirse a conversas públicas mediante teléfonos móbiles. Pode tentar unirse á chamada empregando o navegador web.</string>
     <string name="nc_failed_to_perform_operation">Desculpe, algo foi mal!</string>

+ 5 - 0
app/src/main/res/values-ja-rJP/strings.xml

@@ -9,6 +9,7 @@
     <string name="audio_output_wired_headset">有線ヘッドセット</string>
     <string name="avatar">アバター</string>
     <string name="away">離席中</string>
+    <string name="call_running_since_one_hour">通話が1 時間経過</string>
     <string name="call_without_notification">通知なしで通話</string>
     <string name="choose_avatar_from_cloud">クラウドからアバターを選択</string>
     <string name="clear_status_message">ステータスメッセージを消去</string>
@@ -137,6 +138,7 @@
     <string name="nc_group">グループ</string>
     <string name="nc_groups">グループ</string>
     <string name="nc_guest">ゲスト</string>
+    <string name="nc_guest_access">ゲスト参加</string>
     <string name="nc_guest_access_allow_title">ゲストを許可</string>
     <string name="nc_guest_access_password_dialog_hint">パスワードを入力</string>
     <string name="nc_guest_access_password_summary">パスワードを設定して、パブリックリンクを使用できるユーザーを制限します。</string>
@@ -359,6 +361,9 @@
     <string name="raise_hand">挙手 (r)</string>
     <string name="reactions_tab_all">すべて</string>
     <string name="read_storage_no_permission">ストレージからのファイル共有は権限がなければ不可能です</string>
+    <string name="record_cancel_start">録画開始をキャンセル</string>
+    <string name="record_start_description">録画を開始</string>
+    <string name="record_stop_description">録画を停止</string>
     <string name="save">保存</string>
     <string name="scope_federated_description">信頼できるサーバーのみと同期</string>
     <string name="scope_federated_title">連携</string>

+ 1 - 0
app/src/main/res/values-nb-rNO/strings.xml

@@ -311,6 +311,7 @@
     <string name="thisWeek">Denne uken</string>
     <string name="title_attachments">Vedlegg</string>
     <string name="today">I dag</string>
+    <string name="translate">Oversette</string>
     <string name="translation_device_settings">Enhetsinnstillinger</string>
     <string name="translation_from">Fra</string>
     <string name="translation_to">Til</string>

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

@@ -10,6 +10,7 @@
     <string name="avatar">Аватар</string>
     <string name="away">Отошёл</string>
     <string name="call_more_actions_dialog_headline">Дополнительные настройки звонка</string>
+    <string name="call_running_since_one_hour">Звонок длится уже час</string>
     <string name="call_without_notification">Звонок без уведомления</string>
     <string name="camera_permission_granted">Разрешение на камеру получено. Пожалуйста, выберите камеру снова.</string>
     <string name="choose_avatar_from_cloud">Выберите аватар из облака</string>

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

@@ -10,12 +10,14 @@
     <string name="avatar">Аватар</string>
     <string name="away">Одсутан</string>
     <string name="call_more_actions_dialog_headline">Напредне опције позива</string>
+    <string name="call_running_since_one_hour">Позив траје један сат.</string>
     <string name="call_without_notification">Позив без обавештења</string>
     <string name="camera_permission_granted">Дозвољен је приступ камери. Молимо вас да поново изаберете камеру</string>
     <string name="choose_avatar_from_cloud">Изаберите аватар из облака</string>
     <string name="clear_status_message">Обриши статусну поруку</string>
     <string name="clear_status_message_after">Обриши статусну поруку након</string>
     <string name="close">Затвори</string>
+    <string name="continuous_voice_message_recording">Закључајте снимање да би се гласовна порука непрестано снимала.</string>
     <string name="conversations">Разговори</string>
     <string name="danger_zone">Зона опасности</string>
     <string name="delete_avatar">Обриши аватар</string>
@@ -63,6 +65,7 @@
     <string name="nc_allow_guests">Дозволи госте</string>
     <string name="nc_attendee_pin">Прикачено: %1$s</string>
     <string name="nc_biometric_unlock">Откључај %1$s</string>
+    <string name="nc_bluetooth_permission_hint">Ако желите да укључите bluetooth звучнике, молимо вас да дате дозволу „Оближњи уређаји”</string>
     <string name="nc_call_button_content_description_advanced">Напредне опције позива</string>
     <string name="nc_call_button_content_description_answer_video_call">Одговори као видео позив</string>
     <string name="nc_call_button_content_description_answer_voice_only">Одговори као гласовни позив</string>
@@ -86,6 +89,7 @@
     <string name="nc_call_unknown">%s позив</string>
     <string name="nc_call_video">%s видео позив</string>
     <string name="nc_call_voice">%s гласовни позив</string>
+    <string name="nc_camera_permission_hint">Ако желите да укључите видео комуникацију, молимо вас да дате дозволу „Камера”</string>
     <string name="nc_camera_permission_permanently_denied">Да бисте омогућили видео комуникацију, дозволите приступ камери у системским поставкама.</string>
     <string name="nc_cancel">Откажи</string>
     <string name="nc_capabilities_failed">Грешка приликом дохватања могућности, прекидам</string>
@@ -207,6 +211,7 @@
     <string name="nc_message_quote_cancel_reply">Откажи одговор</string>
     <string name="nc_message_read">Порука је прочитана</string>
     <string name="nc_message_sent">Порука послата</string>
+    <string name="nc_microphone_permission_hint">Ако желите да укључите аудио комуникацију, молимо вас да дате дозволу „Микрофон”</string>
     <string name="nc_microphone_permission_permanently_denied">Да бисте омогућили аудио комуникацију, дозволите приступ микрофону у системским поставкама.</string>
     <string name="nc_missed_call">Имате пропуштен позив од %s</string>
     <string name="nc_moderator">Модератор</string>
@@ -240,7 +245,11 @@
     <string name="nc_participants">Учесници</string>
     <string name="nc_participants_add">Додај учеснике</string>
     <string name="nc_password">Лозинка</string>
+    <string name="nc_permissions_ask">Постави дозволе</string>
+    <string name="nc_permissions_denied">Неке дозволе нису одобрене.</string>
+    <string name="nc_permissions_rationale_dialog_title">Молимо вас да дате дозволе</string>
     <string name="nc_permissions_settings">Отвори поставке</string>
+    <string name="nc_permissions_settings_hint">Молимо вас да одобрите доволе у Подешавања > Дозволе</string>
     <string name="nc_phone_book_integration_account_not_found">Налог није нађен</string>
     <string name="nc_phone_book_integration_chat_via">Чет преко %s</string>
     <string name="nc_pip_microphone_mute">Утули микрофон</string>

+ 5 - 5
app/src/main/res/values-uk/strings.xml

@@ -280,19 +280,19 @@
     <string name="nc_sent_voice" formatted="true">%1$s надсилає голосове повідомлення.</string>
     <string name="nc_sent_voice_you">Ви надіслали голосове повідомлення.</string>
     <string name="nc_server_connect">Перевірка з\'єднання з сервером</string>
-    <string name="nc_server_db_upgrade_needed">Будь ласка, оновіть Вашу %1$s базу даних</string>
+    <string name="nc_server_db_upgrade_needed">Будь ласка, оновіть вашу %1$s базу даних</string>
     <string name="nc_server_failed_to_import_account">Не вдалося імпортувати обраний акаунт.</string>
     <string name="nc_server_helper_text">Посилання на ваш веб-інтерфейс %1$s, коли ви відкриєте його у веб-переглядачі.</string>
     <string name="nc_server_import_account">Імпортувати обліковий запис із застосунку %1$s</string>
     <string name="nc_server_import_account_plain">Імпорт акаунту</string>
     <string name="nc_server_import_accounts">Імпортувати облікові записти із застосунку %1$s</string>
     <string name="nc_server_import_accounts_plain">Імпорт акаунтів</string>
-    <string name="nc_server_maintenance">Будь ласка, вимкніть для %1$s режим обслуговування</string>
-    <string name="nc_server_not_installed">Будь ласка, закінчіть Ваше %1$s встановлення</string>
+    <string name="nc_server_maintenance">Будь ласка, вимкніть режим обслуговування для %1$s </string>
+    <string name="nc_server_not_installed">Будь ласка, завершіть встановлення %1$s </string>
     <string name="nc_server_testing_connection">Перевірка з\'єднання</string>
     <string name="nc_server_unsupported">На сервері не встановлено застосунок \"Talk\", який може підтримуватися</string>
     <string name="nc_server_url">Адреса сервера https://…</string>
-    <string name="nc_server_version">Робота додатка %1$s можлива тільки із серверами %2$s версії 13 або старше</string>
+    <string name="nc_server_version">Застосунок %1$s сумісний з %2$s версії 13 або вище</string>
     <string name="nc_settings">Налаштування</string>
     <string name="nc_settings_account_updated">Замість створення нового облікового запису було виконано оновлення існуючого</string>
     <string name="nc_settings_advanced_title">Додатково</string>
@@ -389,7 +389,7 @@
     <string name="polls_end_poll_confirm">Ви справді хочете закінчити це опитування? Це не можна скасувати.</string>
     <string name="polls_max_votes_reached">Ви не можете голосувати більше ніж за один варіант у цьому опитуванні.</string>
     <string name="polls_multiple_answers">Кілька відповідей</string>
-    <string name="polls_option_delete">Видалити варіант %1$s</string>
+    <string name="polls_option_delete">Вилучити варіант %1$s</string>
     <string name="polls_option_hint">Варіант %1$s</string>
     <string name="polls_options">Параметри</string>
     <string name="polls_private_poll">Приватне опитування</string>

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

@@ -223,8 +223,14 @@
     <string name="raise_hand">Giơ tay</string>
     <string name="reactions_tab_all">Tất cả</string>
     <string name="save">Lưu</string>
+    <string name="scope_federated_description">Chỉ đồng bộ đối với máy chủ tin cậy</string>
     <string name="scope_federated_title">Federated</string>
+    <string name="scope_local_description">Chỉ hiển thị với mọi người trong trường hợp này và khách</string>
+    <string name="scope_local_title">Cục bộ(ngoại tuyến)</string>
+    <string name="scope_private_description">Chỉ hiển thị với những người phù hợp thông qua tích hợp số điện thoại thông qua Talk trên thiết bị di động</string>
     <string name="scope_private_title">Riêng tư</string>
+    <string name="scope_published_description">Đồng bộ với máy chủ tin cậy và sổ danh bạ toàn cầu và công khai</string>
+    <string name="scope_published_title">Đã đăng</string>
     <string name="scroll_to_bottom">Cuộn xuống dưới cùng</string>
     <string name="secondsAgo">vài giây trước</string>
     <string name="selected_list_item">Selected</string>
@@ -248,6 +254,7 @@
     <string name="today">Hôm nay</string>
     <string name="translate">Dịch</string>
     <string name="translation_device_settings">Cài đặt thiết bị</string>
+    <string name="translation_error_message">Không thể phát hiện ngôn ngữ</string>
     <string name="translation_from">Từ</string>
     <string name="translation_to">Tới</string>
     <string name="user_info_address">Địa chỉ</string>

+ 2 - 2
build.gradle

@@ -37,9 +37,9 @@ buildscript {
         classpath 'com.android.tools.build:gradle:8.1.0'
         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}"
         classpath "org.jetbrains.kotlin:kotlin-serialization:${kotlinVersion}"
-        classpath 'com.github.spotbugs.snom:spotbugs-gradle-plugin:5.1.1'
+        classpath 'com.github.spotbugs.snom:spotbugs-gradle-plugin:5.1.3'
         classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.23.1"
-        classpath "org.jlleitschuh.gradle:ktlint-gradle:11.5.0"
+        classpath "org.jlleitschuh.gradle:ktlint-gradle:11.5.1"
 
         // NOTE: Do not place your application dependencies here; they belong
         // in the individual module build.gradle files