浏览代码

Merge master

Signed-off-by: alperozturk <alper_ozturk@proton.me>
alperozturk 1 年之前
父节点
当前提交
8be0dbe1e7
共有 100 个文件被更改,包括 2433 次插入604 次删除
  1. 9 1
      .drone.yml
  2. 1 1
      .github/workflows/analysis.yml
  3. 1 1
      .github/workflows/assembleFlavors.yml
  4. 1 1
      .github/workflows/check.yml
  5. 3 3
      .github/workflows/codeql.yml
  6. 1 1
      .github/workflows/detectWrongSettings.yml
  7. 1 1
      .github/workflows/qa.yml
  8. 1 1
      .github/workflows/scorecard.yml
  9. 1 1
      .github/workflows/screenShotTest.yml
  10. 2 2
      .github/workflows/unit-tests.yml
  11. 1 1
      app/build.gradle
  12. 1161 0
      app/schemas/com.nextcloud.client.database.NextcloudDatabase/74.json
  13. 0 2
      app/src/androidTest/java/com/nextcloud/client/FileDisplayActivityIT.kt
  14. 3 3
      app/src/androidTest/java/com/owncloud/android/UploadIT.java
  15. 2 0
      app/src/androidTest/java/com/owncloud/android/datamodel/OCCapabilityIT.kt
  16. 10 0
      app/src/main/AndroidManifest.xml
  17. 11 4
      app/src/main/java/com/nextcloud/android/sso/InputStreamBinder.java
  18. 4 3
      app/src/main/java/com/nextcloud/client/database/NextcloudDatabase.kt
  19. 3 1
      app/src/main/java/com/nextcloud/client/database/entity/CapabilityEntity.kt
  20. 11 0
      app/src/main/java/com/nextcloud/client/database/migrations/DatabaseMigrationUtil.kt
  21. 0 38
      app/src/main/java/com/nextcloud/client/database/migrations/Migration70to71.kt
  22. 2 2
      app/src/main/java/com/nextcloud/client/di/ComponentsModule.java
  23. 31 14
      app/src/main/java/com/nextcloud/client/editimage/EditImageActivity.kt
  24. 14 4
      app/src/main/java/com/nextcloud/client/files/downloader/FileTransferService.kt
  25. 1 0
      app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt
  26. 4 0
      app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt
  27. 37 6
      app/src/main/java/com/nextcloud/client/jobs/FilesUploadWorker.kt
  28. 13 2
      app/src/main/java/com/nextcloud/client/media/PlayerService.kt
  29. 2 0
      app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java
  30. 2 1
      app/src/main/java/com/owncloud/android/db/ProviderMeta.java
  31. 7 1
      app/src/main/java/com/owncloud/android/files/services/FileDownloader.java
  32. 94 28
      app/src/main/java/com/owncloud/android/files/services/FileUploader.java
  33. 0 257
      app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.java
  34. 249 0
      app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt
  35. 10 16
      app/src/main/java/com/owncloud/android/ui/activity/CopyToClipboardActivity.kt
  36. 4 5
      app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java
  37. 4 5
      app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java
  38. 4 4
      app/src/main/java/com/owncloud/android/ui/activity/UserInfoActivity.java
  39. 0 105
      app/src/main/java/com/owncloud/android/ui/dialog/AccountRemovalConfirmationDialog.kt
  40. 194 0
      app/src/main/java/com/owncloud/android/ui/dialog/AccountRemovalDialog.kt
  41. 9 12
      app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java
  42. 1 1
      app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt
  43. 32 6
      app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragment.java
  44. 28 22
      app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java
  45. 2 0
      app/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.java
  46. 2 0
      app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java
  47. 2 0
      app/src/main/java/com/owncloud/android/ui/preview/PreviewTextFileFragment.java
  48. 28 33
      app/src/main/java/com/owncloud/android/utils/ClipboardUtil.kt
  49. 3 0
      app/src/main/java/com/owncloud/android/utils/ErrorMessageAdapter.java
  50. 13 0
      app/src/main/java/com/owncloud/android/utils/FilesUploadHelper.kt
  51. 154 0
      app/src/main/res/layout/account_removal_dialog.xml
  52. 8 0
      app/src/main/res/values-ar/strings.xml
  53. 11 1
      app/src/main/res/values-b+en+001/strings.xml
  54. 1 0
      app/src/main/res/values-bg-rBG/strings.xml
  55. 1 0
      app/src/main/res/values-br/strings.xml
  56. 1 0
      app/src/main/res/values-ca/strings.xml
  57. 8 0
      app/src/main/res/values-cs-rCZ/strings.xml
  58. 1 0
      app/src/main/res/values-da/strings.xml
  59. 8 0
      app/src/main/res/values-de/strings.xml
  60. 1 0
      app/src/main/res/values-el/strings.xml
  61. 10 0
      app/src/main/res/values-eo/strings.xml
  62. 1 0
      app/src/main/res/values-es-rEC/strings.xml
  63. 1 0
      app/src/main/res/values-es-rMX/strings.xml
  64. 5 0
      app/src/main/res/values-es/strings.xml
  65. 1 0
      app/src/main/res/values-eu/strings.xml
  66. 1 0
      app/src/main/res/values-fa/strings.xml
  67. 1 0
      app/src/main/res/values-fi-rFI/strings.xml
  68. 4 0
      app/src/main/res/values-fr/strings.xml
  69. 8 0
      app/src/main/res/values-gl/strings.xml
  70. 3 2
      app/src/main/res/values-hr/strings.xml
  71. 1 0
      app/src/main/res/values-hu-rHU/strings.xml
  72. 39 1
      app/src/main/res/values-in/strings.xml
  73. 4 0
      app/src/main/res/values-is/strings.xml
  74. 10 0
      app/src/main/res/values-it/strings.xml
  75. 1 0
      app/src/main/res/values-iw/strings.xml
  76. 1 0
      app/src/main/res/values-ja-rJP/strings.xml
  77. 1 0
      app/src/main/res/values-ko/strings.xml
  78. 1 0
      app/src/main/res/values-lt-rLT/strings.xml
  79. 1 0
      app/src/main/res/values-lv/strings.xml
  80. 1 0
      app/src/main/res/values-mk/strings.xml
  81. 1 0
      app/src/main/res/values-nb-rNO/strings.xml
  82. 1 0
      app/src/main/res/values-nl/strings.xml
  83. 3 0
      app/src/main/res/values-pl/strings.xml
  84. 1 0
      app/src/main/res/values-pt-rBR/strings.xml
  85. 1 0
      app/src/main/res/values-pt-rPT/strings.xml
  86. 9 6
      app/src/main/res/values-ro/strings.xml
  87. 1 0
      app/src/main/res/values-ru/strings.xml
  88. 1 0
      app/src/main/res/values-sc/strings.xml
  89. 1 0
      app/src/main/res/values-sk-rSK/strings.xml
  90. 46 0
      app/src/main/res/values-sl/strings.xml
  91. 7 0
      app/src/main/res/values-sr/strings.xml
  92. 7 0
      app/src/main/res/values-sv/strings.xml
  93. 1 0
      app/src/main/res/values-th-rTH/strings.xml
  94. 5 1
      app/src/main/res/values-tr/strings.xml
  95. 8 2
      app/src/main/res/values-uk/strings.xml
  96. 7 0
      app/src/main/res/values-zh-rCN/strings.xml
  97. 10 0
      app/src/main/res/values-zh-rHK/strings.xml
  98. 8 0
      app/src/main/res/values-zh-rTW/strings.xml
  99. 6 1
      app/src/main/res/values/strings.xml
  100. 1 1
      build.gradle

+ 9 - 1
.drone.yml

@@ -36,6 +36,7 @@ services:
     commands:
       - BRANCH="$SERVER_VERSION" /usr/local/bin/initnc.sh
       - echo 127.0.0.1 server >> /etc/hosts
+      - apt-get update && apt-get install -y composer
       - su www-data -c "OC_PASS=user1 php /var/www/html/occ user:add --password-from-env --display-name='User One' user1"
       - su www-data -c "OC_PASS=user2 php /var/www/html/occ user:add --password-from-env --display-name='User Two' user2"
       - su www-data -c "OC_PASS=user3 php /var/www/html/occ user:add --password-from-env --display-name='User Three' user3"
@@ -49,6 +50,9 @@ services:
       - su www-data -c "php /var/www/html/occ app:enable text"
       - su www-data -c "git clone -b $SERVER_VERSION https://github.com/nextcloud/end_to_end_encryption.git /var/www/html/apps/end_to_end_encryption/"
       - su www-data -c "php /var/www/html/occ app:enable end_to_end_encryption"
+      - su www-data -c "git clone -b $SERVER_VERSION https://github.com/nextcloud/photos.git /var/www/html/apps/photos/"
+      - su www-data -c "cd /var/www/html/apps/photos; composer install"
+      - su www-data -c "php /var/www/html/occ app:enable -f photos"
       - /usr/local/bin/run.sh
 
 trigger:
@@ -90,6 +94,7 @@ services:
     commands:
       - /usr/local/bin/initnc.sh
       - echo 127.0.0.1 server >> /etc/hosts
+      - apt-get update && apt-get install -y composer
       - su www-data -c "OC_PASS=user1 php /var/www/html/occ user:add --password-from-env --display-name='User One' user1"
       - su www-data -c "OC_PASS=user2 php /var/www/html/occ user:add --password-from-env --display-name='User Two' user2"
       - su www-data -c "OC_PASS=user3 php /var/www/html/occ user:add --password-from-env --display-name='User Three' user3"
@@ -103,6 +108,9 @@ services:
       - su www-data -c "php /var/www/html/occ app:enable text"
       - su www-data -c "git clone -b master https://github.com/nextcloud/end_to_end_encryption/  /var/www/html/apps/end_to_end_encryption/"
       - su www-data -c "php /var/www/html/occ app:enable end_to_end_encryption"
+      - su www-data -c "git clone https://github.com/nextcloud/photos.git /var/www/html/apps/photos/"
+      - su www-data -c "cd /var/www/html/apps/photos; composer install"
+      - su www-data -c "php /var/www/html/occ app:enable -f photos"
       - /usr/local/bin/run.sh
 
 trigger:
@@ -171,6 +179,6 @@ name: GIT_TOKEN
 data: XIoa9IYq+xQ+N5iln8dlpWv0jV6ROr7HuE24ioUr4uQ8m8SjyH0yognWYLYLqnbTKrFWlFZiEMQTH/sZiWjRFvV1iL0=
 ---
 kind: signature
-hmac: b78dcc477ff74ccbd7877df011090783847f8b5215a994be6597408bd735b524
+hmac: cf7f9b6403072500d986d4979375676729a9104f98b0c53fba5198c478cccab4
 
 ...

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

@@ -38,7 +38,7 @@ jobs:
                     repository: ${{ steps.get-vars.outputs.repo }}
                     ref: ${{ steps.get-vars.outputs.branch }}
             -   name: Set up JDK 17
-                uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3.13.0
+                uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0
                 with:
                     distribution: "temurin"
                     java-version: 17

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

@@ -21,7 +21,7 @@ jobs:
         steps:
             -   uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v3
             -   name: set up JDK 17
-                uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3
+                uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v3
                 with:
                     distribution: "temurin"
                     java-version: 17

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

@@ -21,7 +21,7 @@ jobs:
         steps:
             -   uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v3
             -   name: Set up JDK 17
-                uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3
+                uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v3
                 with:
                     distribution: "temurin"
                     java-version: 17

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

@@ -32,11 +32,11 @@ jobs:
         with:
           swap-size-gb: 10
       - name: Initialize CodeQL
-        uses: github/codeql-action/init@66b90a5db151a8042fa97405c6cf843bbe433f7b # v2.22.7
+        uses: github/codeql-action/init@407ffafae6a767df3e0230c3df91b6443ae8df75 # v2.22.8
         with:
           languages: ${{ matrix.language }}
       - name: Set up JDK 17
-        uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3.13.0
+        uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0
         with:
           distribution: "temurin"
           java-version: 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@66b90a5db151a8042fa97405c6cf843bbe433f7b # v2.22.7
+        uses: github/codeql-action/analyze@407ffafae6a767df3e0230c3df91b6443ae8df75 # v2.22.8

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

@@ -18,7 +18,7 @@ jobs:
         steps:
             -   uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v3
             -   name: Set up JDK 17
-                uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3
+                uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v3
                 with:
                     distribution: "temurin"
                     java-version: 17

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

@@ -22,7 +22,7 @@ jobs:
             -   uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v3
                 if: ${{ steps.check-secrets.outputs.ok == 'true' }}
             -   name: set up JDK 17
-                uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3
+                uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v3
                 if: ${{ steps.check-secrets.outputs.ok == 'true' }}
                 with:
                     distribution: "temurin"

+ 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@66b90a5db151a8042fa97405c6cf843bbe433f7b # v2.22.7
+        uses: github/codeql-action/upload-sarif@407ffafae6a767df3e0230c3df91b6443ae8df75 # v2.22.8
         with:
           sarif_file: results.sarif

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

@@ -40,7 +40,7 @@ jobs:
                         ~/.android/adb*
                     key: avd-${{ matrix.api-level }}
 
-            -   uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3
+            -   uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v3
                 with:
                     distribution: "temurin"
                     java-version: 17

+ 2 - 2
.github/workflows/unit-tests.yml

@@ -20,7 +20,7 @@ jobs:
         steps:
             -   uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
             -   name: Set up JDK 17
-                uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3.13.0
+                uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0
                 with:
                     distribution: "temurin"
                     java-version: 17
@@ -30,7 +30,7 @@ jobs:
                 if: ${{ always() }}
                 run: scripts/deleteOldComments.sh "test" "Unit" ${{github.event.number}}
             -   name: Run unit tests with coverage
-                uses: gradle/gradle-build-action@842c587ad8aa4c68eeba24c396e15af4c2e9f30a # v2.9.0
+                uses: gradle/gradle-build-action@87a9a15658c426a54dd469d4fc7dc1a73ca9d4a6 # v2.10.0
                 with:
                     arguments: jacocoTestGplayDebugUnitTest
             -   name: Upload failing results

+ 1 - 1
app/build.gradle

@@ -377,7 +377,7 @@ dependencies {
     gplayImplementation "com.google.firebase:firebase-messaging:23.2.1"
     gplayImplementation 'com.google.android.play:review-ktx:2.0.1'
 
-    implementation 'com.github.nextcloud.android-common:ui:0.12.0'
+    implementation 'com.github.nextcloud.android-common:ui:0.13.0'
 
     implementation "androidx.room:room-runtime:$roomVersion"
     ksp "androidx.room:room-compiler:$roomVersion"

+ 1161 - 0
app/schemas/com.nextcloud.client.database.NextcloudDatabase/74.json

@@ -0,0 +1,1161 @@
+{
+  "formatVersion": 1,
+  "database": {
+    "version": 74,
+    "identityHash": "7e73c045ac6d52d6c7c1626eefbc21e9",
+    "entities": [
+      {
+        "tableName": "arbitrary_data",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `cloud_id` TEXT, `key` TEXT, `value` TEXT)",
+        "fields": [
+          {
+            "fieldPath": "id",
+            "columnName": "_id",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "cloudId",
+            "columnName": "cloud_id",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "key",
+            "columnName": "key",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "value",
+            "columnName": "value",
+            "affinity": "TEXT",
+            "notNull": false
+          }
+        ],
+        "primaryKey": {
+          "autoGenerate": true,
+          "columnNames": [
+            "_id"
+          ]
+        },
+        "indices": [],
+        "foreignKeys": []
+      },
+      {
+        "tableName": "capabilities",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `account` TEXT, `version_mayor` INTEGER, `version_minor` INTEGER, `version_micro` INTEGER, `version_string` TEXT, `version_edition` TEXT, `extended_support` INTEGER, `core_pollinterval` INTEGER, `sharing_api_enabled` INTEGER, `sharing_public_enabled` INTEGER, `sharing_public_password_enforced` INTEGER, `sharing_public_expire_date_enabled` INTEGER, `sharing_public_expire_date_days` INTEGER, `sharing_public_expire_date_enforced` INTEGER, `sharing_public_send_mail` INTEGER, `sharing_public_upload` INTEGER, `sharing_user_send_mail` INTEGER, `sharing_resharing` INTEGER, `sharing_federation_outgoing` INTEGER, `sharing_federation_incoming` INTEGER, `files_bigfilechunking` INTEGER, `files_undelete` INTEGER, `files_versioning` INTEGER, `external_links` INTEGER, `server_name` TEXT, `server_color` TEXT, `server_text_color` TEXT, `server_element_color` TEXT, `server_slogan` TEXT, `server_logo` TEXT, `background_url` TEXT, `end_to_end_encryption` INTEGER, `end_to_end_encryption_keys_exist` INTEGER, `activity` INTEGER, `background_default` INTEGER, `background_plain` INTEGER, `richdocument` INTEGER, `richdocument_mimetype_list` TEXT, `richdocument_direct_editing` INTEGER, `richdocument_direct_templates` INTEGER, `richdocument_optional_mimetype_list` TEXT, `sharing_public_ask_for_optional_password` INTEGER, `richdocument_product_name` TEXT, `direct_editing_etag` TEXT, `user_status` INTEGER, `user_status_supports_emoji` INTEGER, `etag` TEXT, `files_locking_version` TEXT, `groupfolders` INTEGER, `drop_account` INTEGER)",
+        "fields": [
+          {
+            "fieldPath": "id",
+            "columnName": "_id",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "accountName",
+            "columnName": "account",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "versionMajor",
+            "columnName": "version_mayor",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "versionMinor",
+            "columnName": "version_minor",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "versionMicro",
+            "columnName": "version_micro",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "versionString",
+            "columnName": "version_string",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "versionEditor",
+            "columnName": "version_edition",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "extendedSupport",
+            "columnName": "extended_support",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "corePollinterval",
+            "columnName": "core_pollinterval",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "sharingApiEnabled",
+            "columnName": "sharing_api_enabled",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "sharingPublicEnabled",
+            "columnName": "sharing_public_enabled",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "sharingPublicPasswordEnforced",
+            "columnName": "sharing_public_password_enforced",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "sharingPublicExpireDateEnabled",
+            "columnName": "sharing_public_expire_date_enabled",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "sharingPublicExpireDateDays",
+            "columnName": "sharing_public_expire_date_days",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "sharingPublicExpireDateEnforced",
+            "columnName": "sharing_public_expire_date_enforced",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "sharingPublicSendMail",
+            "columnName": "sharing_public_send_mail",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "sharingPublicUpload",
+            "columnName": "sharing_public_upload",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "sharingUserSendMail",
+            "columnName": "sharing_user_send_mail",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "sharingResharing",
+            "columnName": "sharing_resharing",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "sharingFederationOutgoing",
+            "columnName": "sharing_federation_outgoing",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "sharingFederationIncoming",
+            "columnName": "sharing_federation_incoming",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "filesBigfilechunking",
+            "columnName": "files_bigfilechunking",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "filesUndelete",
+            "columnName": "files_undelete",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "filesVersioning",
+            "columnName": "files_versioning",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "externalLinks",
+            "columnName": "external_links",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "serverName",
+            "columnName": "server_name",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "serverColor",
+            "columnName": "server_color",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "serverTextColor",
+            "columnName": "server_text_color",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "serverElementColor",
+            "columnName": "server_element_color",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "serverSlogan",
+            "columnName": "server_slogan",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "serverLogo",
+            "columnName": "server_logo",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "serverBackgroundUrl",
+            "columnName": "background_url",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "endToEndEncryption",
+            "columnName": "end_to_end_encryption",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "endToEndEncryptionKeysExist",
+            "columnName": "end_to_end_encryption_keys_exist",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "activity",
+            "columnName": "activity",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "serverBackgroundDefault",
+            "columnName": "background_default",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "serverBackgroundPlain",
+            "columnName": "background_plain",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "richdocument",
+            "columnName": "richdocument",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "richdocumentMimetypeList",
+            "columnName": "richdocument_mimetype_list",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "richdocumentDirectEditing",
+            "columnName": "richdocument_direct_editing",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "richdocumentTemplates",
+            "columnName": "richdocument_direct_templates",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "richdocumentOptionalMimetypeList",
+            "columnName": "richdocument_optional_mimetype_list",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "sharingPublicAskForOptionalPassword",
+            "columnName": "sharing_public_ask_for_optional_password",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "richdocumentProductName",
+            "columnName": "richdocument_product_name",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "directEditingEtag",
+            "columnName": "direct_editing_etag",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "userStatus",
+            "columnName": "user_status",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "userStatusSupportsEmoji",
+            "columnName": "user_status_supports_emoji",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "etag",
+            "columnName": "etag",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "filesLockingVersion",
+            "columnName": "files_locking_version",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "groupfolders",
+            "columnName": "groupfolders",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "dropAccount",
+            "columnName": "drop_account",
+            "affinity": "INTEGER",
+            "notNull": false
+          }
+        ],
+        "primaryKey": {
+          "autoGenerate": true,
+          "columnNames": [
+            "_id"
+          ]
+        },
+        "indices": [],
+        "foreignKeys": []
+      },
+      {
+        "tableName": "external_links",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `icon_url` TEXT, `language` TEXT, `type` INTEGER, `name` TEXT, `url` TEXT, `redirect` INTEGER)",
+        "fields": [
+          {
+            "fieldPath": "id",
+            "columnName": "_id",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "iconUrl",
+            "columnName": "icon_url",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "language",
+            "columnName": "language",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "type",
+            "columnName": "type",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "name",
+            "columnName": "name",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "url",
+            "columnName": "url",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "redirect",
+            "columnName": "redirect",
+            "affinity": "INTEGER",
+            "notNull": false
+          }
+        ],
+        "primaryKey": {
+          "autoGenerate": true,
+          "columnNames": [
+            "_id"
+          ]
+        },
+        "indices": [],
+        "foreignKeys": []
+      },
+      {
+        "tableName": "filelist",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `filename` TEXT, `encrypted_filename` TEXT, `path` TEXT, `path_decrypted` TEXT, `parent` INTEGER, `created` INTEGER, `modified` INTEGER, `content_type` TEXT, `content_length` INTEGER, `media_path` TEXT, `file_owner` TEXT, `last_sync_date` INTEGER, `last_sync_date_for_data` INTEGER, `modified_at_last_sync_for_data` INTEGER, `etag` TEXT, `etag_on_server` TEXT, `share_by_link` INTEGER, `permissions` TEXT, `remote_id` TEXT, `local_id` INTEGER NOT NULL DEFAULT -1, `update_thumbnail` INTEGER, `is_downloading` INTEGER, `favorite` INTEGER, `is_encrypted` INTEGER, `etag_in_conflict` TEXT, `shared_via_users` INTEGER, `mount_type` INTEGER, `has_preview` INTEGER, `unread_comments_count` INTEGER, `owner_id` TEXT, `owner_display_name` TEXT, `note` TEXT, `sharees` TEXT, `rich_workspace` TEXT, `metadata_size` TEXT, `locked` INTEGER, `lock_type` INTEGER, `lock_owner` TEXT, `lock_owner_display_name` TEXT, `lock_owner_editor` TEXT, `lock_timestamp` INTEGER, `lock_timeout` INTEGER, `lock_token` TEXT, `tags` TEXT, `metadata_gps` TEXT)",
+        "fields": [
+          {
+            "fieldPath": "id",
+            "columnName": "_id",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "name",
+            "columnName": "filename",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "encryptedName",
+            "columnName": "encrypted_filename",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "path",
+            "columnName": "path",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "pathDecrypted",
+            "columnName": "path_decrypted",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "parent",
+            "columnName": "parent",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "creation",
+            "columnName": "created",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "modified",
+            "columnName": "modified",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "contentType",
+            "columnName": "content_type",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "contentLength",
+            "columnName": "content_length",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "storagePath",
+            "columnName": "media_path",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "accountOwner",
+            "columnName": "file_owner",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "lastSyncDate",
+            "columnName": "last_sync_date",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "lastSyncDateForData",
+            "columnName": "last_sync_date_for_data",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "modifiedAtLastSyncForData",
+            "columnName": "modified_at_last_sync_for_data",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "etag",
+            "columnName": "etag",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "etagOnServer",
+            "columnName": "etag_on_server",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "sharedViaLink",
+            "columnName": "share_by_link",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "permissions",
+            "columnName": "permissions",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "remoteId",
+            "columnName": "remote_id",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "localId",
+            "columnName": "local_id",
+            "affinity": "INTEGER",
+            "notNull": true,
+            "defaultValue": "-1"
+          },
+          {
+            "fieldPath": "updateThumbnail",
+            "columnName": "update_thumbnail",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "isDownloading",
+            "columnName": "is_downloading",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "favorite",
+            "columnName": "favorite",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "isEncrypted",
+            "columnName": "is_encrypted",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "etagInConflict",
+            "columnName": "etag_in_conflict",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "sharedWithSharee",
+            "columnName": "shared_via_users",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "mountType",
+            "columnName": "mount_type",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "hasPreview",
+            "columnName": "has_preview",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "unreadCommentsCount",
+            "columnName": "unread_comments_count",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "ownerId",
+            "columnName": "owner_id",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "ownerDisplayName",
+            "columnName": "owner_display_name",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "note",
+            "columnName": "note",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "sharees",
+            "columnName": "sharees",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "richWorkspace",
+            "columnName": "rich_workspace",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "metadataSize",
+            "columnName": "metadata_size",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "locked",
+            "columnName": "locked",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "lockType",
+            "columnName": "lock_type",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "lockOwner",
+            "columnName": "lock_owner",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "lockOwnerDisplayName",
+            "columnName": "lock_owner_display_name",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "lockOwnerEditor",
+            "columnName": "lock_owner_editor",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "lockTimestamp",
+            "columnName": "lock_timestamp",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "lockTimeout",
+            "columnName": "lock_timeout",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "lockToken",
+            "columnName": "lock_token",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "tags",
+            "columnName": "tags",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "metadataGPS",
+            "columnName": "metadata_gps",
+            "affinity": "TEXT",
+            "notNull": false
+          }
+        ],
+        "primaryKey": {
+          "autoGenerate": true,
+          "columnNames": [
+            "_id"
+          ]
+        },
+        "indices": [],
+        "foreignKeys": []
+      },
+      {
+        "tableName": "filesystem",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `local_path` TEXT, `is_folder` INTEGER, `found_at` INTEGER, `upload_triggered` INTEGER, `syncedfolder_id` TEXT, `crc32` TEXT, `modified_at` INTEGER)",
+        "fields": [
+          {
+            "fieldPath": "id",
+            "columnName": "_id",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "localPath",
+            "columnName": "local_path",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "fileIsFolder",
+            "columnName": "is_folder",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "fileFoundRecently",
+            "columnName": "found_at",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "fileSentForUpload",
+            "columnName": "upload_triggered",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "syncedFolderId",
+            "columnName": "syncedfolder_id",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "crc32",
+            "columnName": "crc32",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "fileModified",
+            "columnName": "modified_at",
+            "affinity": "INTEGER",
+            "notNull": false
+          }
+        ],
+        "primaryKey": {
+          "autoGenerate": true,
+          "columnNames": [
+            "_id"
+          ]
+        },
+        "indices": [],
+        "foreignKeys": []
+      },
+      {
+        "tableName": "ocshares",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `file_source` INTEGER, `item_source` INTEGER, `share_type` INTEGER, `shate_with` TEXT, `path` TEXT, `permissions` INTEGER, `shared_date` INTEGER, `expiration_date` INTEGER, `token` TEXT, `shared_with_display_name` TEXT, `is_directory` INTEGER, `user_id` INTEGER, `id_remote_shared` INTEGER, `owner_share` TEXT, `is_password_protected` INTEGER, `note` TEXT, `hide_download` INTEGER, `share_link` TEXT, `share_label` TEXT)",
+        "fields": [
+          {
+            "fieldPath": "id",
+            "columnName": "_id",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "fileSource",
+            "columnName": "file_source",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "itemSource",
+            "columnName": "item_source",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "shareType",
+            "columnName": "share_type",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "shareWith",
+            "columnName": "shate_with",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "path",
+            "columnName": "path",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "permissions",
+            "columnName": "permissions",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "sharedDate",
+            "columnName": "shared_date",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "expirationDate",
+            "columnName": "expiration_date",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "token",
+            "columnName": "token",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "shareWithDisplayName",
+            "columnName": "shared_with_display_name",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "isDirectory",
+            "columnName": "is_directory",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "userId",
+            "columnName": "user_id",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "idRemoteShared",
+            "columnName": "id_remote_shared",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "accountOwner",
+            "columnName": "owner_share",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "isPasswordProtected",
+            "columnName": "is_password_protected",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "note",
+            "columnName": "note",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "hideDownload",
+            "columnName": "hide_download",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "shareLink",
+            "columnName": "share_link",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "shareLabel",
+            "columnName": "share_label",
+            "affinity": "TEXT",
+            "notNull": false
+          }
+        ],
+        "primaryKey": {
+          "autoGenerate": true,
+          "columnNames": [
+            "_id"
+          ]
+        },
+        "indices": [],
+        "foreignKeys": []
+      },
+      {
+        "tableName": "synced_folders",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `local_path` TEXT, `remote_path` TEXT, `wifi_only` INTEGER, `charging_only` INTEGER, `existing` INTEGER, `enabled` INTEGER, `enabled_timestamp_ms` INTEGER, `subfolder_by_date` INTEGER, `account` TEXT, `upload_option` INTEGER, `name_collision_policy` INTEGER, `type` INTEGER, `hidden` INTEGER, `sub_folder_rule` INTEGER)",
+        "fields": [
+          {
+            "fieldPath": "id",
+            "columnName": "_id",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "localPath",
+            "columnName": "local_path",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "remotePath",
+            "columnName": "remote_path",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "wifiOnly",
+            "columnName": "wifi_only",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "chargingOnly",
+            "columnName": "charging_only",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "existing",
+            "columnName": "existing",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "enabled",
+            "columnName": "enabled",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "enabledTimestampMs",
+            "columnName": "enabled_timestamp_ms",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "subfolderByDate",
+            "columnName": "subfolder_by_date",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "account",
+            "columnName": "account",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "uploadAction",
+            "columnName": "upload_option",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "nameCollisionPolicy",
+            "columnName": "name_collision_policy",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "type",
+            "columnName": "type",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "hidden",
+            "columnName": "hidden",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "subFolderRule",
+            "columnName": "sub_folder_rule",
+            "affinity": "INTEGER",
+            "notNull": false
+          }
+        ],
+        "primaryKey": {
+          "autoGenerate": true,
+          "columnNames": [
+            "_id"
+          ]
+        },
+        "indices": [],
+        "foreignKeys": []
+      },
+      {
+        "tableName": "list_of_uploads",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `local_path` TEXT, `remote_path` TEXT, `account_name` TEXT, `file_size` INTEGER, `status` INTEGER, `local_behaviour` INTEGER, `upload_time` INTEGER, `name_collision_policy` INTEGER, `is_create_remote_folder` INTEGER, `upload_end_timestamp` INTEGER, `last_result` INTEGER, `is_while_charging_only` INTEGER, `is_wifi_only` INTEGER, `created_by` INTEGER, `folder_unlock_token` TEXT)",
+        "fields": [
+          {
+            "fieldPath": "id",
+            "columnName": "_id",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "localPath",
+            "columnName": "local_path",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "remotePath",
+            "columnName": "remote_path",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "accountName",
+            "columnName": "account_name",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "fileSize",
+            "columnName": "file_size",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "status",
+            "columnName": "status",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "localBehaviour",
+            "columnName": "local_behaviour",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "uploadTime",
+            "columnName": "upload_time",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "nameCollisionPolicy",
+            "columnName": "name_collision_policy",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "isCreateRemoteFolder",
+            "columnName": "is_create_remote_folder",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "uploadEndTimestamp",
+            "columnName": "upload_end_timestamp",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "lastResult",
+            "columnName": "last_result",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "isWhileChargingOnly",
+            "columnName": "is_while_charging_only",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "isWifiOnly",
+            "columnName": "is_wifi_only",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "createdBy",
+            "columnName": "created_by",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "folderUnlockToken",
+            "columnName": "folder_unlock_token",
+            "affinity": "TEXT",
+            "notNull": false
+          }
+        ],
+        "primaryKey": {
+          "autoGenerate": true,
+          "columnNames": [
+            "_id"
+          ]
+        },
+        "indices": [],
+        "foreignKeys": []
+      },
+      {
+        "tableName": "virtual",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `type` TEXT, `ocfile_id` INTEGER)",
+        "fields": [
+          {
+            "fieldPath": "id",
+            "columnName": "_id",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "type",
+            "columnName": "type",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "ocFileId",
+            "columnName": "ocfile_id",
+            "affinity": "INTEGER",
+            "notNull": false
+          }
+        ],
+        "primaryKey": {
+          "autoGenerate": true,
+          "columnNames": [
+            "_id"
+          ]
+        },
+        "indices": [],
+        "foreignKeys": []
+      }
+    ],
+    "views": [],
+    "setupQueries": [
+      "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '7e73c045ac6d52d6c7c1626eefbc21e9')"
+    ]
+  }
+}

+ 0 - 2
app/src/androidTest/java/com/nextcloud/client/FileDisplayActivityIT.kt

@@ -26,7 +26,6 @@ import androidx.test.espresso.Espresso
 import androidx.test.espresso.Espresso.onView
 import androidx.test.espresso.action.ViewActions.click
 import androidx.test.espresso.action.ViewActions.closeSoftKeyboard
-import androidx.test.espresso.action.ViewActions.scrollTo
 import androidx.test.espresso.assertion.ViewAssertions.matches
 import androidx.test.espresso.contrib.DrawerActions
 import androidx.test.espresso.contrib.NavigationViewActions
@@ -241,7 +240,6 @@ class FileDisplayActivityIT : AbstractOnServerIT() {
 
         // browse into folder
         onView(withId(R.id.list_root))
-            .perform(scrollTo())
             .perform(closeSoftKeyboard())
             .perform(
                 RecyclerViewActions.actionOnItemAtPosition<OCFileListItemViewHolder>(

+ 3 - 3
app/src/androidTest/java/com/owncloud/android/UploadIT.java

@@ -475,7 +475,7 @@ public class UploadIT extends AbstractOnServerIT {
         testOnlyOnServer(NextcloudVersion.nextcloud_27);
 
         File file = getFile("gps.jpg");
-        String remotePath = "/gps.jpg";
+        String remotePath = "/metadata.jpg";
         OCUpload ocUpload = new OCUpload(file.getAbsolutePath(), remotePath, account.name);
 
         assertTrue(
@@ -512,7 +512,7 @@ public class UploadIT extends AbstractOnServerIT {
 
         OCFile ocFile = null;
         for (OCFile f : files) {
-            if (f.getFileName().equals("gps.jpg")) {
+            if (f.getFileName().equals("metadata.jpg")) {
                 ocFile = f;
                 break;
             }
@@ -520,8 +520,8 @@ public class UploadIT extends AbstractOnServerIT {
 
         assertNotNull(ocFile);
         assertEquals(remotePath, ocFile.getRemotePath());
-        assertEquals(new ImageDimension(300f, 200f), ocFile.getImageDimension());
         assertEquals(new GeoLocation(64, -46), ocFile.getGeoLocation());
+        assertEquals(new ImageDimension(300f, 200f), ocFile.getImageDimension());
     }
 
     private void verifyStoragePath(OCFile file) {

+ 2 - 0
app/src/androidTest/java/com/owncloud/android/datamodel/OCCapabilityIT.kt

@@ -37,6 +37,7 @@ class OCCapabilityIT : AbstractIT() {
         capability.etag = "123"
         capability.userStatus = CapabilityBooleanType.TRUE
         capability.userStatusSupportsEmoji = CapabilityBooleanType.TRUE
+        capability.dropAccount = CapabilityBooleanType.TRUE
 
         fileDataStorageManager.saveCapabilities(capability)
 
@@ -45,5 +46,6 @@ class OCCapabilityIT : AbstractIT() {
         assertEquals(capability.etag, newCapability.etag)
         assertEquals(capability.userStatus, newCapability.userStatus)
         assertEquals(capability.userStatusSupportsEmoji, newCapability.userStatusSupportsEmoji)
+        assertEquals(capability.dropAccount, newCapability.dropAccount)
     }
 }

+ 10 - 0
app/src/main/AndroidManifest.xml

@@ -72,6 +72,9 @@
     <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
     <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
 
+    <!-- Needed for Android 14 (API level 34) -->
+    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
+    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
 
     <!-- Some Chromebooks don't support touch. Although not essential,
          it's a good idea to explicitly include this declaration. -->
@@ -166,6 +169,9 @@
         <receiver
             android:name="com.nextcloud.client.jobs.NotificationWork$NotificationReceiver"
             android:exported="false" />
+        <receiver
+            android:name="com.owncloud.android.files.services.FileUploader$UploadNotificationActionReceiver"
+            android:exported="false" />
         <receiver
             android:name="com.nextcloud.client.widget.DashboardWidgetProvider"
             android:exported="false">
@@ -378,15 +384,19 @@
             android:exported="false" />
         <service
             android:name=".files.services.FileDownloader"
+            android:foregroundServiceType="dataSync"
             android:exported="false" />
         <service
             android:name="com.nextcloud.client.files.downloader.FileTransferService"
+            android:foregroundServiceType="dataSync"
             android:exported="false" />
         <service
             android:name=".files.services.FileUploader"
+            android:foregroundServiceType="dataSync"
             android:exported="false" />
         <service
             android:name="com.nextcloud.client.media.PlayerService"
+            android:foregroundServiceType="mediaPlayback"
             android:exported="false" />
 
         <activity

+ 11 - 4
app/src/main/java/com/nextcloud/android/sso/InputStreamBinder.java

@@ -457,16 +457,23 @@ public class InputStreamBinder extends IInputStreamService.Stub {
     }
 
     private boolean isValid(NextcloudRequest request) {
-        String callingPackageName = context.getPackageManager().getNameForUid(Binder.getCallingUid());
+        String[] callingPackageNames = context.getPackageManager().getPackagesForUid(Binder.getCallingUid());
 
         SharedPreferences sharedPreferences = context.getSharedPreferences(SSO_SHARED_PREFERENCE,
                                                                            Context.MODE_PRIVATE);
-        String hash = sharedPreferences.getString(callingPackageName + DELIMITER + request.getAccountName(), "");
-        return validateToken(hash, request.getToken());
+        for (String callingPackageName : callingPackageNames) {
+            String hash = sharedPreferences.getString(callingPackageName + DELIMITER + request.getAccountName(), "");
+            if (hash.isEmpty())
+                continue;
+            if (validateToken(hash, request.getToken())) {
+                return true;
+            }
+        }
+        return false;
     }
 
     private boolean validateToken(String hash, String token) {
-        if (hash.isEmpty() || !hash.contains("$")) {
+        if (!hash.contains("$")) {
             throw new IllegalStateException(EXCEPTION_INVALID_TOKEN);
         }
 

+ 4 - 3
app/src/main/java/com/nextcloud/client/database/NextcloudDatabase.kt

@@ -40,8 +40,8 @@ import com.nextcloud.client.database.entity.ShareEntity
 import com.nextcloud.client.database.entity.SyncedFolderEntity
 import com.nextcloud.client.database.entity.UploadEntity
 import com.nextcloud.client.database.entity.VirtualEntity
+import com.nextcloud.client.database.migrations.DatabaseMigrationUtil
 import com.nextcloud.client.database.migrations.Migration67to68
-import com.nextcloud.client.database.migrations.Migration70to71
 import com.nextcloud.client.database.migrations.RoomMigration
 import com.nextcloud.client.database.migrations.addLegacyMigrations
 import com.owncloud.android.db.ProviderMeta
@@ -64,8 +64,10 @@ import com.owncloud.android.db.ProviderMeta
         AutoMigration(from = 66, to = 67),
         AutoMigration(from = 68, to = 69),
         AutoMigration(from = 69, to = 70),
+        AutoMigration(from = 70, to = 71, spec = DatabaseMigrationUtil.ResetCapabilitiesPostMigration::class),
         AutoMigration(from = 71, to = 72),
-        AutoMigration(from = 72, to = 73)
+        AutoMigration(from = 72, to = 73),
+        AutoMigration(from = 73, to = 74, spec = DatabaseMigrationUtil.ResetCapabilitiesPostMigration::class)
     ],
     exportSchema = true
 )
@@ -95,7 +97,6 @@ abstract class NextcloudDatabase : RoomDatabase() {
                     .addLegacyMigrations(clock, context)
                     .addMigrations(RoomMigration())
                     .addMigrations(Migration67to68())
-                    .addMigrations(Migration70to71())
                     .fallbackToDestructiveMigration()
                     .build()
             }

+ 3 - 1
app/src/main/java/com/nextcloud/client/database/entity/CapabilityEntity.kt

@@ -129,5 +129,7 @@ data class CapabilityEntity(
     @ColumnInfo(name = ProviderTableMeta.CAPABILITIES_FILES_LOCKING_VERSION)
     val filesLockingVersion: String?,
     @ColumnInfo(name = ProviderTableMeta.CAPABILITIES_GROUPFOLDERS)
-    val groupfolders: Int?
+    val groupfolders: Int?,
+    @ColumnInfo(name = ProviderTableMeta.CAPABILITIES_DROP_ACCOUNT)
+    val dropAccount: Int?
 )

+ 11 - 0
app/src/main/java/com/nextcloud/client/database/migrations/DatabaseMigrationUtil.kt

@@ -22,6 +22,7 @@
 
 package com.nextcloud.client.database.migrations
 
+import androidx.room.migration.AutoMigrationSpec
 import androidx.sqlite.db.SupportSQLiteDatabase
 
 object DatabaseMigrationUtil {
@@ -102,4 +103,14 @@ object DatabaseMigrationUtil {
         database.execSQL("DROP TABLE $tableName")
         database.execSQL("ALTER TABLE $newTableTempName RENAME TO $tableName")
     }
+
+    /**
+     * Room AutoMigrationSpec to reset capabilities post migration.
+     */
+    class ResetCapabilitiesPostMigration : AutoMigrationSpec {
+        override fun onPostMigrate(db: SupportSQLiteDatabase) {
+            resetCapabilities(db)
+            super.onPostMigrate(db)
+        }
+    }
 }

+ 0 - 38
app/src/main/java/com/nextcloud/client/database/migrations/Migration70to71.kt

@@ -1,38 +0,0 @@
-/*
- * Nextcloud Android client application
- *
- *  @author Álvaro Brey
- *  Copyright (C) 2023 Álvaro Brey
- *  Copyright (C) 2023 Nextcloud GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package com.nextcloud.client.database.migrations
-
-import androidx.room.migration.Migration
-import androidx.sqlite.db.SupportSQLiteDatabase
-
-/**
- * Migration from version 70 to 71.
- *
- * resets capabilities to show groupfolder
- */
-@Suppress("MagicNumber")
-class Migration70to71 : Migration(70, 71) {
-    override fun migrate(database: SupportSQLiteDatabase) {
-        DatabaseMigrationUtil.resetCapabilities(database)
-    }
-}

+ 2 - 2
app/src/main/java/com/nextcloud/client/di/ComponentsModule.java

@@ -81,7 +81,7 @@ import com.owncloud.android.ui.activity.ToolbarActivity;
 import com.owncloud.android.ui.activity.UploadFilesActivity;
 import com.owncloud.android.ui.activity.UploadListActivity;
 import com.owncloud.android.ui.activity.UserInfoActivity;
-import com.owncloud.android.ui.dialog.AccountRemovalConfirmationDialog;
+import com.owncloud.android.ui.dialog.AccountRemovalDialog;
 import com.owncloud.android.ui.dialog.ChooseRichDocumentsTemplateDialogFragment;
 import com.owncloud.android.ui.dialog.ChooseTemplateDialogFragment;
 import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
@@ -270,7 +270,7 @@ abstract class ComponentsModule {
     abstract ChooseTemplateDialogFragment chooseTemplateDialogFragment();
 
     @ContributesAndroidInjector
-    abstract AccountRemovalConfirmationDialog accountRemovalConfirmationDialog();
+    abstract AccountRemovalDialog accountRemovalDialog();
 
     @ContributesAndroidInjector
     abstract ChooseRichDocumentsTemplateDialogFragment chooseRichDocumentsTemplateDialogFragment();

+ 31 - 14
app/src/main/java/com/nextcloud/client/editimage/EditImageActivity.kt

@@ -30,8 +30,11 @@ import android.view.View
 import androidx.appcompat.content.res.AppCompatResources
 import androidx.core.content.ContextCompat
 import androidx.core.graphics.drawable.DrawableCompat
+import androidx.core.view.WindowCompat
+import androidx.core.view.WindowInsetsCompat
 import com.canhub.cropper.CropImageView
 import com.nextcloud.client.di.Injectable
+import com.nextcloud.utils.extensions.getParcelableArgument
 import com.owncloud.android.R
 import com.owncloud.android.databinding.ActivityEditImageBinding
 import com.owncloud.android.datamodel.OCFile
@@ -80,7 +83,8 @@ class EditImageActivity :
         binding = ActivityEditImageBinding.inflate(layoutInflater)
         setContentView(binding.root)
 
-        file = intent.extras?.getParcelable(EXTRA_FILE) ?: throw IllegalArgumentException("Missing file argument")
+        file = intent.extras?.getParcelableArgument(EXTRA_FILE, OCFile::class.java)
+            ?: throw IllegalArgumentException("Missing file argument")
 
         setSupportActionBar(binding.toolbar)
         supportActionBar?.apply {
@@ -88,9 +92,11 @@ class EditImageActivity :
             setDisplayHomeAsUpEnabled(true)
         }
 
+        val windowInsetsController = WindowCompat.getInsetsController(window, window.decorView)
+        windowInsetsController.hide(WindowInsetsCompat.Type.statusBars())
+
         window.statusBarColor = ContextCompat.getColor(this, R.color.black)
         window.navigationBarColor = getColor(R.color.black)
-        window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN
 
         setupCropper()
     }
@@ -105,17 +111,19 @@ class EditImageActivity :
             " " + getString(R.string.image_editor_file_edited_suffix) +
             resultUri?.substring(resultUri.lastIndexOf('.'))
 
-        FilesUploadHelper().uploadNewFiles(
-            user = storageManager.user,
-            localPaths = arrayOf(resultUri!!),
-            remotePaths = arrayOf(file.parentRemotePath + File.separator + newFileName),
-            createRemoteFolder = false,
-            createdBy = UploadFileOperation.CREATED_BY_USER,
-            requiresWifi = false,
-            requiresCharging = false,
-            nameCollisionPolicy = NameCollisionPolicy.RENAME,
-            localBehavior = FileUploader.LOCAL_BEHAVIOUR_DELETE
-        )
+        resultUri?.let {
+            FilesUploadHelper().uploadNewFiles(
+                user = storageManager.user,
+                localPaths = arrayOf(it),
+                remotePaths = arrayOf(file.parentRemotePath + File.separator + newFileName),
+                createRemoteFolder = false,
+                createdBy = UploadFileOperation.CREATED_BY_USER,
+                requiresWifi = false,
+                requiresCharging = false,
+                nameCollisionPolicy = NameCollisionPolicy.RENAME,
+                localBehavior = FileUploader.LOCAL_BEHAVIOUR_DELETE
+            )
+        }
     }
 
     override fun onSetImageUriComplete(view: CropImageView, uri: Uri, error: Exception?) {
@@ -147,6 +155,7 @@ class EditImageActivity :
             finish()
             true
         }
+
         else -> {
             finish()
             true
@@ -184,7 +193,15 @@ class EditImageActivity :
         // determine output file format
         format = when (file.mimeType) {
             MimeType.PNG -> Bitmap.CompressFormat.PNG
-            MimeType.WEBP -> Bitmap.CompressFormat.WEBP
+            MimeType.WEBP -> {
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+                    Bitmap.CompressFormat.WEBP_LOSSY
+                } else {
+                    @Suppress("DEPRECATION")
+                    Bitmap.CompressFormat.WEBP
+                }
+            }
+
             else -> Bitmap.CompressFormat.JPEG
         }
     }

+ 14 - 4
app/src/main/java/com/nextcloud/client/files/downloader/FileTransferService.kt

@@ -22,6 +22,8 @@ package com.nextcloud.client.files.downloader
 import android.app.Service
 import android.content.Context
 import android.content.Intent
+import android.content.pm.ServiceInfo
+import android.os.Build
 import android.os.IBinder
 import com.nextcloud.client.account.User
 import com.nextcloud.client.core.AsyncRunner
@@ -107,10 +109,18 @@ class FileTransferService : Service() {
         }
 
         if (!isRunning) {
-            startForeground(
-                AppNotificationManager.TRANSFER_NOTIFICATION_ID,
-                notificationsManager.buildDownloadServiceForegroundNotification()
-            )
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+                startForeground(
+                    AppNotificationManager.TRANSFER_NOTIFICATION_ID,
+                    notificationsManager.buildDownloadServiceForegroundNotification(),
+                    ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
+                )
+            } else {
+                startForeground(
+                    AppNotificationManager.TRANSFER_NOTIFICATION_ID,
+                    notificationsManager.buildDownloadServiceForegroundNotification()
+                )
+            }
         }
 
         val request: Request = intent.getParcelableExtra(EXTRA_REQUEST)!!

+ 1 - 0
app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt

@@ -137,6 +137,7 @@ interface BackgroundJobManager {
     fun startAccountRemovalJob(accountName: String, remoteWipe: Boolean)
     fun startFilesUploadJob(user: User)
     fun getFileUploads(user: User): LiveData<List<JobInfo>>
+    fun cancelFilesUploadJob(user: User)
 
     fun startPdfGenerateAndUploadWork(user: User, uploadFolder: String, imagePaths: List<String>, pdfPath: String)
 

+ 4 - 0
app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt

@@ -461,6 +461,10 @@ internal class BackgroundJobManagerImpl(
         return workInfo.map { it -> it.map { fromWorkInfo(it) ?: JobInfo() } }
     }
 
+    override fun cancelFilesUploadJob(user: User) {
+        workManager.cancelJob(JOB_FILES_UPLOAD, user)
+    }
+
     override fun startPdfGenerateAndUploadWork(
         user: User,
         uploadFolder: String,

+ 37 - 6
app/src/main/java/com/nextcloud/client/jobs/FilesUploadWorker.kt

@@ -43,6 +43,7 @@ import com.owncloud.android.datamodel.FileDataStorageManager
 import com.owncloud.android.datamodel.ThumbnailsCacheManager
 import com.owncloud.android.datamodel.UploadsStorageManager
 import com.owncloud.android.db.OCUpload
+import com.owncloud.android.files.services.FileUploader
 import com.owncloud.android.lib.common.OwnCloudAccount
 import com.owncloud.android.lib.common.OwnCloudClientManagerFactory
 import com.owncloud.android.lib.common.network.OnDatatransferProgressListener
@@ -76,6 +77,7 @@ class FilesUploadWorker(
     private val notificationManager: NotificationManager =
         context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
     private val fileUploaderDelegate = FileUploaderDelegate()
+    private var currentUploadFileOperation: UploadFileOperation? = null
 
     override fun doWork(): Result {
         val accountName = inputData.getString(ACCOUNT)
@@ -89,7 +91,7 @@ class FilesUploadWorker(
          * they will be present in the pages that follow.
          */
         var currentPage = uploadsStorageManager.getCurrentAndPendingUploadsForAccountPageAscById(-1, accountName)
-        while (currentPage.isNotEmpty()) {
+        while (currentPage.isNotEmpty() && !isStopped) {
             Log_OC.d(TAG, "Handling ${currentPage.size} uploads for account $accountName")
             val lastId = currentPage.last().uploadId
             handlePendingUploads(currentPage, accountName)
@@ -105,11 +107,16 @@ class FilesUploadWorker(
         val user = userAccountManager.getUser(accountName)
 
         for (upload in uploads) {
+            if (isStopped) {
+                break
+            }
             // create upload file operation
             if (user.isPresent) {
                 val uploadFileOperation = createUploadFileOperation(upload, user.get())
 
+                currentUploadFileOperation = uploadFileOperation
                 val result = upload(uploadFileOperation, user.get())
+                currentUploadFileOperation = null
 
                 fileUploaderDelegate.sendBroadcastUploadFinished(
                     uploadFileOperation,
@@ -172,13 +179,16 @@ class FilesUploadWorker(
             Log_OC.e(TAG, "Error uploading", e)
             uploadResult = RemoteOperationResult<Any?>(e)
         } finally {
-            uploadsStorageManager.updateDatabaseUploadResult(uploadResult, uploadFileOperation)
+            // only update db if operation finished and worker didn't get canceled
+            if (!(isStopped && uploadResult.isCancelled)) {
+                uploadsStorageManager.updateDatabaseUploadResult(uploadResult, uploadFileOperation)
 
-            // / notify result
-            notifyUploadResult(uploadFileOperation, uploadResult)
+                // / notify result
+                notifyUploadResult(uploadFileOperation, uploadResult)
 
-            // cancel notification
-            notificationManager.cancel(FOREGROUND_SERVICE_ID)
+                // cancel notification
+                notificationManager.cancel(FOREGROUND_SERVICE_ID)
+            }
         }
 
         return uploadResult
@@ -188,6 +198,18 @@ class FilesUploadWorker(
      * adapted from [com.owncloud.android.files.services.FileUploader.notifyUploadStart]
      */
     private fun createNotification(uploadFileOperation: UploadFileOperation) {
+        val notificationActionIntent = Intent(context, FileUploader.UploadNotificationActionReceiver::class.java)
+        notificationActionIntent.putExtra(FileUploader.EXTRA_ACCOUNT_NAME, uploadFileOperation.user.accountName)
+        notificationActionIntent.putExtra(FileUploader.EXTRA_REMOTE_PATH, uploadFileOperation.remotePath)
+        notificationActionIntent.action = FileUploader.ACTION_CANCEL_BROADCAST
+
+        val pendingIntent = PendingIntent.getBroadcast(
+            context,
+            SecureRandom().nextInt(),
+            notificationActionIntent,
+            PendingIntent.FLAG_IMMUTABLE
+        )
+
         notificationBuilder
             .setOngoing(true)
             .setSmallIcon(R.drawable.notification_icon)
@@ -200,6 +222,8 @@ class FilesUploadWorker(
                     uploadFileOperation.fileName
                 )
             )
+            .clearActions() // to make sure there is only one action
+            .addAction(R.drawable.ic_action_cancel_grey, context.getString(R.string.common_cancel), pendingIntent)
 
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
             notificationBuilder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_UPLOAD)
@@ -266,6 +290,7 @@ class FilesUploadWorker(
                 .setAutoCancel(true)
                 .setOngoing(false)
                 .setProgress(0, 0, false)
+                .clearActions()
 
             val content = ErrorMessageAdapter.getErrorCauseMessage(uploadResult, uploadFileOperation, context.resources)
 
@@ -357,6 +382,12 @@ class FilesUploadWorker(
         lastPercent = percent
     }
 
+    override fun onStopped() {
+        super.onStopped()
+        currentUploadFileOperation?.cancel(null)
+        notificationManager.cancel(FOREGROUND_SERVICE_ID)
+    }
+
     companion object {
         val TAG: String = FilesUploadWorker::class.java.simpleName
         private const val FOREGROUND_SERVICE_ID: Int = 412

+ 13 - 2
app/src/main/java/com/nextcloud/client/media/PlayerService.kt

@@ -22,7 +22,9 @@ package com.nextcloud.client.media
 import android.app.PendingIntent
 import android.app.Service
 import android.content.Intent
+import android.content.pm.ServiceInfo
 import android.media.AudioManager
+import android.os.Build
 import android.os.Bundle
 import android.os.IBinder
 import android.widget.MediaController
@@ -167,11 +169,20 @@ class PlayerService : Service() {
         notificationBuilder.setContentTitle(ticker)
         notificationBuilder.setContentText(content)
 
-        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
             notificationBuilder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_MEDIA)
         }
 
-        startForeground(R.string.media_notif_ticker, notificationBuilder.build())
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+            startForeground(
+                R.string.media_notif_ticker,
+                notificationBuilder.build(),
+                ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
+            )
+        } else {
+            startForeground(R.string.media_notif_ticker, notificationBuilder.build())
+        }
+
         isRunning = true
     }
 

+ 2 - 0
app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java

@@ -1947,6 +1947,7 @@ public class FileDataStorageManager {
         contentValues.put(ProviderTableMeta.CAPABILITIES_FILES_LOCKING_VERSION,
                           capability.getFilesLockingVersion());
         contentValues.put(ProviderTableMeta.CAPABILITIES_GROUPFOLDERS, capability.getGroupfolders().getValue());
+        contentValues.put(ProviderTableMeta.CAPABILITIES_DROP_ACCOUNT, capability.getDropAccount().getValue());
 
         return contentValues;
     }
@@ -2103,6 +2104,7 @@ public class FileDataStorageManager {
             capability.setFilesLockingVersion(
                 getString(cursor, ProviderTableMeta.CAPABILITIES_FILES_LOCKING_VERSION));
             capability.setGroupfolders(getBoolean(cursor, ProviderTableMeta.CAPABILITIES_GROUPFOLDERS));
+            capability.setDropAccount(getBoolean(cursor, ProviderTableMeta.CAPABILITIES_DROP_ACCOUNT));
         }
         return capability;
     }

+ 2 - 1
app/src/main/java/com/owncloud/android/db/ProviderMeta.java

@@ -35,7 +35,7 @@ import java.util.List;
  */
 public class ProviderMeta {
     public static final String DB_NAME = "filelist";
-    public static final int DB_VERSION = 73;
+    public static final int DB_VERSION = 74;
 
     private ProviderMeta() {
         // No instance
@@ -259,6 +259,7 @@ public class ProviderMeta {
         public static final String CAPABILITIES_USER_STATUS = "user_status";
         public static final String CAPABILITIES_USER_STATUS_SUPPORTS_EMOJI = "user_status_supports_emoji";
         public static final String CAPABILITIES_GROUPFOLDERS = "groupfolders";
+        public static final String CAPABILITIES_DROP_ACCOUNT = "drop_account";
 
         //Columns of Uploads table
         public static final String UPLOADS_LOCAL_PATH = "local_path";

+ 7 - 1
app/src/main/java/com/owncloud/android/files/services/FileDownloader.java

@@ -28,8 +28,10 @@ import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.Service;
 import android.content.Intent;
+import android.content.pm.ServiceInfo;
 import android.graphics.BitmapFactory;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
@@ -200,7 +202,11 @@ public class FileDownloader extends Service
     public int onStartCommand(Intent intent, int flags, int startId) {
         Log_OC.d(TAG, "Starting command with id " + startId);
 
-        startForeground(FOREGROUND_SERVICE_ID, mNotification);
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+            startForeground(FOREGROUND_SERVICE_ID, mNotification, ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC);
+        } else {
+            startForeground(FOREGROUND_SERVICE_ID, mNotification);
+        }
 
         if (intent == null || !intent.hasExtra(EXTRA_USER) || !intent.hasExtra(EXTRA_FILE)) {
             Log_OC.e(TAG, "Not enough information provided in intent");

+ 94 - 28
app/src/main/java/com/owncloud/android/files/services/FileUploader.java

@@ -34,8 +34,10 @@ import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.Service;
+import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ServiceInfo;
 import android.graphics.BitmapFactory;
 import android.os.Binder;
 import android.os.Build;
@@ -89,6 +91,7 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.NoSuchElementException;
 
 import javax.annotation.Nullable;
 import javax.inject.Inject;
@@ -126,6 +129,10 @@ public class FileUploader extends Service
     public static final String EXTRA_LINKED_TO_PATH = "LINKED_TO";
     public static final String ACCOUNT_NAME = "ACCOUNT_NAME";
 
+    public static final String EXTRA_ACCOUNT_NAME = "ACCOUNT_NAME";
+    public static final String ACTION_CANCEL_BROADCAST = "CANCEL";
+    public static final String ACTION_PAUSE_BROADCAST = "PAUSE";
+
     private static final int FOREGROUND_SERVICE_ID = 411;
 
     public static final String KEY_FILE = "FILE";
@@ -196,11 +203,13 @@ public class FileUploader extends Service
     private Notification mNotification;
     private Looper mServiceLooper;
     private ServiceHandler mServiceHandler;
-    private IBinder mBinder;
+    private static IBinder mBinder;
     private OwnCloudClient mUploadClient;
     private Account mCurrentAccount;
     private FileDataStorageManager mStorageManager;
 
+    private SecureRandom secureRandomGenerator = new SecureRandom();
+
     @Inject UserAccountManager accountManager;
     @Inject UploadsStorageManager mUploadsStorageManager;
     @Inject ConnectivityService connectivityService;
@@ -231,6 +240,7 @@ public class FileUploader extends Service
     /**
      * Service initialization
      */
+    @SuppressFBWarnings("ST")
     @Override
     public void onCreate() {
         super.onCreate();
@@ -278,6 +288,7 @@ public class FileUploader extends Service
     /**
      * Service clean up
      */
+    @SuppressFBWarnings("ST")
     @Override
     public void onDestroy() {
         Log_OC.v(TAG, "Destroying service");
@@ -304,7 +315,11 @@ public class FileUploader extends Service
     public int onStartCommand(Intent intent, int flags, int startId) {
         Log_OC.d(TAG, "Starting command with id " + startId);
 
-        startForeground(FOREGROUND_SERVICE_ID, mNotification);
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+            startForeground(FOREGROUND_SERVICE_ID, mNotification, ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC);
+        } else {
+            startForeground(FOREGROUND_SERVICE_ID, mNotification);
+        }
 
         if (intent == null) {
             Log_OC.e(TAG, "Intent is null");
@@ -602,7 +617,7 @@ public class FileUploader extends Service
 
     /**
      * Core upload method: sends the file(s) to upload WARNING: legacy code, must be in sync with @{{@link
-     * FilesUploadWorker#upload(UploadFileOperation, User)}
+     * FilesUploadWorker upload(UploadFileOperation, User)}
      *
      * @param uploadKey Key to access the upload to perform, contained in mPendingUploads
      */
@@ -702,6 +717,12 @@ public class FileUploader extends Service
      */
     private void notifyUploadStart(UploadFileOperation upload) {
         // / create status notification with a progress bar
+        Intent notificationActionIntent = new Intent(getApplicationContext(),UploadNotificationActionReceiver.class);
+        notificationActionIntent.putExtra(EXTRA_ACCOUNT_NAME,upload.getUser().getAccountName());
+        notificationActionIntent.putExtra(EXTRA_REMOTE_PATH,upload.getRemotePath());
+        notificationActionIntent.setAction(ACTION_CANCEL_BROADCAST);
+
+        PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(),secureRandomGenerator.nextInt(),notificationActionIntent, PendingIntent.FLAG_IMMUTABLE);
         mLastPercent = 0;
         mNotificationBuilder = NotificationUtils.newNotificationBuilder(this, viewThemeUtils);
         mNotificationBuilder
@@ -712,7 +733,10 @@ public class FileUploader extends Service
             .setProgress(100, 0, false)
             .setContentText(
                 String.format(getString(R.string.uploader_upload_in_progress_content), 0, upload.getFileName())
-                           );
+                           )
+            .clearActions() // to make sure there is only one action
+            .addAction(R.drawable.ic_action_cancel_grey,getApplicationContext().getString(R.string.common_cancel),pendingIntent);
+
 
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
             mNotificationBuilder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_UPLOAD);
@@ -805,7 +829,8 @@ public class FileUploader extends Service
                 .setContentTitle(getString(tickerId))
                 .setAutoCancel(true)
                 .setOngoing(false)
-                .setProgress(0, 0, false);
+                .setProgress(0, 0, false)
+                .clearActions();
 
             content = ErrorMessageAdapter.getErrorCauseMessage(uploadResult, upload, getResources());
 
@@ -853,7 +878,7 @@ public class FileUploader extends Service
 
             mNotificationBuilder.setContentText(content);
             if (!uploadResult.isSuccess()) {
-                mNotificationManager.notify((new SecureRandom()).nextInt(), mNotificationBuilder.build());
+                mNotificationManager.notify(secureRandomGenerator.nextInt(), mNotificationBuilder.build());
             }
         }
     }
@@ -1152,24 +1177,34 @@ public class FileUploader extends Service
          * @param remotePath  Remote target of the upload
          * @param resultCode  Setting result code will pause rather than cancel the job
          */
-        private void cancel(String accountName, String remotePath, @Nullable ResultCode resultCode) {
-            Pair<UploadFileOperation, String> removeResult = mPendingUploads.remove(accountName, remotePath);
-            UploadFileOperation upload = removeResult.first;
-            if (upload == null && mCurrentUpload != null && mCurrentAccount != null &&
-                mCurrentUpload.getRemotePath().startsWith(remotePath) && accountName.equals(mCurrentAccount.name)) {
+        public void cancel(String accountName, String remotePath, @Nullable ResultCode resultCode) {
+            // Cancel for Android version >= Android 11
+            if (useFilesUploadWorker(getApplicationContext())){
+                try{
+                    new FilesUploadHelper().cancelFileUpload(remotePath, accountManager.getUser(accountName).get());
+                }catch(NoSuchElementException e){
+                    Log_OC.e(TAG,"Error cancelling current upload because user does not exist!");
+                }
+            } else {
+                // Cancel for Android version <= Android 10
+                Pair<UploadFileOperation, String> removeResult = mPendingUploads.remove(accountName, remotePath);
+                UploadFileOperation upload = removeResult.first;
+                if (upload == null && mCurrentUpload != null && mCurrentAccount != null &&
+                    mCurrentUpload.getRemotePath().startsWith(remotePath) && accountName.equals(mCurrentAccount.name)) {
 
-                upload = mCurrentUpload;
-            }
+                    upload = mCurrentUpload;
+                }
 
-            if (upload != null) {
-                upload.cancel(resultCode);
-                // need to update now table in mUploadsStorageManager,
-                // since the operation will not get to be run by FileUploader#uploadFile
-                if (resultCode != null) {
-                    mUploadsStorageManager.updateDatabaseUploadResult(new RemoteOperationResult(resultCode), upload);
-                    notifyUploadResult(upload, new RemoteOperationResult(resultCode));
-                } else {
-                    mUploadsStorageManager.removeUpload(accountName, remotePath);
+                if (upload != null) {
+                    upload.cancel(resultCode);
+                    // need to update now table in mUploadsStorageManager,
+                    // since the operation will not get to be run by FileUploader#uploadFile
+                    if (resultCode != null) {
+                        mUploadsStorageManager.updateDatabaseUploadResult(new RemoteOperationResult(resultCode), upload);
+                        notifyUploadResult(upload, new RemoteOperationResult(resultCode));
+                    } else {
+                        mUploadsStorageManager.removeUpload(accountName, remotePath);
+                    }
                 }
             }
         }
@@ -1180,16 +1215,19 @@ public class FileUploader extends Service
          * @param user Nextcloud user
          */
         public void cancel(User user) {
-            if (mCurrentUpload != null && mCurrentUpload.getUser().nameEquals(user)) {
-                mCurrentUpload.cancel(ResultCode.CANCELLED);
-            }
-            cancelPendingUploads(user.getAccountName());
+            cancel(user.getAccountName());
         }
 
         public void cancel(String accountName) {
-            if (mCurrentUpload != null && mCurrentUpload.getUser().nameEquals(accountName)) {
-                mCurrentUpload.cancel(ResultCode.CANCELLED);
+            cancelPendingUploads(accountName);
+            if (useFilesUploadWorker(getApplicationContext())) {
+                new FilesUploadHelper().restartUploadJob(accountManager.getUser(accountName).get());
+            }else{
+                if (mCurrentUpload != null && mCurrentUpload.getUser().nameEquals(accountName)) {
+                    mCurrentUpload.cancel(ResultCode.CANCELLED);
+                }
             }
+
         }
 
         public void clearListeners() {
@@ -1389,4 +1427,32 @@ public class FileUploader extends Service
             mService.stopSelf(msg.arg1);
         }
     }
+
+
+    /**
+     * When cancel action in upload notification is pressed, cancel upload of item
+     */
+    public static class UploadNotificationActionReceiver extends BroadcastReceiver {
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+
+            String accountName = intent.getStringExtra(EXTRA_ACCOUNT_NAME);
+            String remotePath = intent.getStringExtra(EXTRA_REMOTE_PATH);
+            String action = intent.getAction();
+
+            if (ACTION_CANCEL_BROADCAST.equals(action)) {
+                Log_OC.d(TAG, "Cancel broadcast received for file " + remotePath + " at " + System.currentTimeMillis());
+
+                if (accountName == null || remotePath == null) return;
+
+                FileUploaderBinder uploadBinder = (FileUploaderBinder) mBinder;
+                uploadBinder.cancel(accountName, remotePath, null);
+            }else if(ACTION_PAUSE_BROADCAST.equals(action)){
+
+            } else {
+                Log_OC.d(TAG, "Unknown action to perform as UploadNotificationActionReceiver.");
+            }
+        }
+    }
 }

+ 0 - 257
app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.java

@@ -1,257 +0,0 @@
-/*
- * ownCloud Android client application
- *
- * @author Bartek Przybylski
- * @author David A. Velasco Copyright (C) 2012 Bartek Przybylski Copyright (C) 2016 ownCloud Inc.
- * <p>
- * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation.
- * <p>
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
- * details.
- * <p/>
- * You should have received a copy of the GNU General Public License along with this program.  If not, see
- * <http://www.gnu.org/licenses/>.
- */
-
-package com.owncloud.android.ui.activity;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.widget.Toast;
-
-import com.nextcloud.client.account.User;
-import com.nextcloud.java.util.Optional;
-import com.owncloud.android.R;
-import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.datamodel.UploadsStorageManager;
-import com.owncloud.android.db.OCUpload;
-import com.owncloud.android.files.services.FileDownloader;
-import com.owncloud.android.files.services.FileUploader;
-import com.owncloud.android.files.services.NameCollisionPolicy;
-import com.owncloud.android.lib.common.operations.RemoteOperationResult;
-import com.owncloud.android.lib.common.utils.Log_OC;
-import com.owncloud.android.lib.resources.files.ReadFileRemoteOperation;
-import com.owncloud.android.lib.resources.files.model.RemoteFile;
-import com.owncloud.android.ui.dialog.ConflictsResolveDialog;
-import com.owncloud.android.ui.dialog.ConflictsResolveDialog.Decision;
-import com.owncloud.android.ui.dialog.ConflictsResolveDialog.OnConflictDecisionMadeListener;
-import com.owncloud.android.utils.FileStorageUtils;
-
-import javax.inject.Inject;
-
-import androidx.annotation.NonNull;
-import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentTransaction;
-
-
-/**
- * Wrapper activity which will be launched if keep-in-sync file will be modified by external application.
- */
-public class ConflictsResolveActivity extends FileActivity implements OnConflictDecisionMadeListener {
-    /**
-     * A nullable upload entry that must be removed when and if the conflict is resolved.
-     */
-    public static final String EXTRA_CONFLICT_UPLOAD_ID = "CONFLICT_UPLOAD_ID";
-    /**
-     * Specify the upload local behaviour when there is no CONFLICT_UPLOAD.
-     */
-    public static final String EXTRA_LOCAL_BEHAVIOUR = "LOCAL_BEHAVIOUR";
-    public static final String EXTRA_EXISTING_FILE = "EXISTING_FILE";
-
-    private static final String TAG = ConflictsResolveActivity.class.getSimpleName();
-
-    @Inject UploadsStorageManager uploadsStorageManager;
-
-    private long conflictUploadId;
-    private OCFile existingFile;
-    private OCFile newFile;
-    private int localBehaviour = FileUploader.LOCAL_BEHAVIOUR_FORGET;
-    protected OnConflictDecisionMadeListener listener;
-
-    public static Intent createIntent(OCFile file,
-                                      User user,
-                                      long conflictUploadId,
-                                      Integer flag,
-                                      Context context) {
-        Intent intent = new Intent(context, ConflictsResolveActivity.class);
-        if (flag != null) {
-            intent.setFlags(intent.getFlags() | flag);
-        }
-        intent.putExtra(EXTRA_FILE, file);
-        intent.putExtra(EXTRA_USER, user);
-        intent.putExtra(EXTRA_CONFLICT_UPLOAD_ID, conflictUploadId);
-
-        return intent;
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        if (savedInstanceState != null) {
-            conflictUploadId = savedInstanceState.getLong(EXTRA_CONFLICT_UPLOAD_ID);
-            existingFile = savedInstanceState.getParcelable(EXTRA_EXISTING_FILE);
-            localBehaviour = savedInstanceState.getInt(EXTRA_LOCAL_BEHAVIOUR);
-        } else {
-            conflictUploadId = getIntent().getLongExtra(EXTRA_CONFLICT_UPLOAD_ID, -1);
-            existingFile = getIntent().getParcelableExtra(EXTRA_EXISTING_FILE);
-            localBehaviour = getIntent().getIntExtra(EXTRA_LOCAL_BEHAVIOUR, localBehaviour);
-        }
-
-        OCUpload upload = uploadsStorageManager.getUploadById(conflictUploadId);
-
-        if (upload != null) {
-            localBehaviour = upload.getLocalAction();
-        }
-
-        // new file was modified locally in file system
-        newFile = getFile();
-
-        listener = decision -> {
-            OCFile file = newFile; // local file got changed, so either upload it or replace it again by server
-            // version
-            User user = getUser().orElseThrow(RuntimeException::new);
-            switch (decision) {
-                case CANCEL:
-                    // nothing to do
-                    break;
-                case KEEP_LOCAL: // Upload
-                    FileUploader.uploadUpdateFile(
-                        getBaseContext(),
-                        user,
-                        file,
-                        localBehaviour,
-                        NameCollisionPolicy.OVERWRITE
-                                                 );
-
-                    uploadsStorageManager.removeUpload(upload);
-                    break;
-                case KEEP_BOTH: // Upload
-                    FileUploader.uploadUpdateFile(
-                        getBaseContext(),
-                        user,
-                        file,
-                        localBehaviour,
-                        NameCollisionPolicy.RENAME
-                                                 );
-
-                    uploadsStorageManager.removeUpload(upload);
-                    break;
-                case KEEP_SERVER: // Download
-                    if (!shouldDeleteLocal()) {
-                        // Overwrite local file
-                        Intent intent = new Intent(getBaseContext(), FileDownloader.class);
-                        intent.putExtra(FileDownloader.EXTRA_USER, getUser().orElseThrow(RuntimeException::new));
-                        intent.putExtra(FileDownloader.EXTRA_FILE, file);
-                        intent.putExtra(EXTRA_CONFLICT_UPLOAD_ID, conflictUploadId);
-                        startService(intent);
-                    } else {
-                        uploadsStorageManager.removeUpload(upload);
-                    }
-                    break;
-            }
-
-            finish();
-        };
-    }
-
-    @Override
-    protected void onSaveInstanceState(@NonNull Bundle outState) {
-        super.onSaveInstanceState(outState);
-
-        outState.putLong(EXTRA_CONFLICT_UPLOAD_ID, conflictUploadId);
-        outState.putParcelable(EXTRA_EXISTING_FILE, existingFile);
-        outState.putInt(EXTRA_LOCAL_BEHAVIOUR, localBehaviour);
-    }
-
-    @Override
-    public void conflictDecisionMade(Decision decision) {
-        listener.conflictDecisionMade(decision);
-    }
-
-    @Override
-    protected void onStart() {
-        super.onStart();
-        if (getAccount() == null) {
-            finish();
-            return;
-        }
-
-        if (newFile == null) {
-            Log_OC.e(TAG, "No file received");
-            finish();
-            return;
-        }
-
-        if (existingFile == null) {
-            // fetch info of existing file from server
-            ReadFileRemoteOperation operation = new ReadFileRemoteOperation(newFile.getRemotePath());
-
-            new Thread(() -> {
-                try {
-                    RemoteOperationResult result = operation.execute(getAccount(), this);
-
-                    if (result.isSuccess()) {
-                        existingFile = FileStorageUtils.fillOCFile((RemoteFile) result.getData().get(0));
-                        existingFile.setLastSyncDateForProperties(System.currentTimeMillis());
-
-                        startDialog();
-                    } else {
-                        Log_OC.e(TAG, "ReadFileRemoteOp returned failure with code: " + result.getHttpCode());
-                        showErrorAndFinish();
-                    }
-                } catch (Exception e) {
-                    Log_OC.e(TAG, "Error when trying to fetch remote file", e);
-                    showErrorAndFinish();
-                }
-
-
-            }).start();
-        } else {
-            startDialog();
-        }
-    }
-
-    private void startDialog() {
-        Optional<User> userOptional = getUser();
-
-        if (!userOptional.isPresent()) {
-            Log_OC.e(TAG, "User not present");
-            showErrorAndFinish();
-        }
-
-        // Check whether the file is contained in the current Account
-        Fragment prev = getSupportFragmentManager().findFragmentByTag("conflictDialog");
-
-        FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
-        if (prev != null) {
-            fragmentTransaction.remove(prev);
-        }
-
-        if (existingFile != null && getStorageManager().fileExists(newFile.getRemotePath())) {
-            ConflictsResolveDialog dialog = ConflictsResolveDialog.newInstance(existingFile,
-                                                                               newFile,
-                                                                               userOptional.get());
-            dialog.show(fragmentTransaction, "conflictDialog");
-        } else {
-            // Account was changed to a different one - just finish
-            Log_OC.e(TAG, "Account was changed, finishing");
-            showErrorAndFinish();
-        }
-    }
-
-    private void showErrorAndFinish() {
-        runOnUiThread(() -> Toast.makeText(this, R.string.conflict_dialog_error, Toast.LENGTH_LONG).show());
-        finish();
-    }
-
-    /**
-     * @return whether the local version of the files is to be deleted.
-     */
-    private boolean shouldDeleteLocal() {
-        return localBehaviour == FileUploader.LOCAL_BEHAVIOUR_DELETE;
-    }
-}

+ 249 - 0
app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt

@@ -0,0 +1,249 @@
+/*
+ * ownCloud Android client application
+ *
+ * @author Bartek Przybylski
+ * @author David A. Velasco Copyright (C) 2012 Bartek Przybylski Copyright (C) 2016 ownCloud Inc.
+ * <p>
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation.
+ * <p>
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ * details.
+ * <p/>
+ * You should have received a copy of the GNU General Public License along with this program.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+package com.owncloud.android.ui.activity
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.widget.Toast
+import com.nextcloud.client.account.User
+import com.nextcloud.utils.extensions.getParcelableArgument
+import com.owncloud.android.R
+import com.owncloud.android.datamodel.OCFile
+import com.owncloud.android.datamodel.UploadsStorageManager
+import com.owncloud.android.db.OCUpload
+import com.owncloud.android.files.services.FileDownloader
+import com.owncloud.android.files.services.FileUploader
+import com.owncloud.android.files.services.NameCollisionPolicy
+import com.owncloud.android.lib.common.utils.Log_OC
+import com.owncloud.android.lib.resources.files.ReadFileRemoteOperation
+import com.owncloud.android.lib.resources.files.model.RemoteFile
+import com.owncloud.android.ui.dialog.ConflictsResolveDialog
+import com.owncloud.android.ui.dialog.ConflictsResolveDialog.Decision
+import com.owncloud.android.ui.dialog.ConflictsResolveDialog.OnConflictDecisionMadeListener
+import com.owncloud.android.utils.FileStorageUtils
+import javax.inject.Inject
+
+/**
+ * Wrapper activity which will be launched if keep-in-sync file will be modified by external application.
+ */
+class ConflictsResolveActivity : FileActivity(), OnConflictDecisionMadeListener {
+
+    @JvmField
+    @Inject
+    var uploadsStorageManager: UploadsStorageManager? = null
+
+    private var conflictUploadId: Long = 0
+    private var existingFile: OCFile? = null
+    private var newFile: OCFile? = null
+    private var localBehaviour = FileUploader.LOCAL_BEHAVIOUR_FORGET
+
+    @JvmField
+    var listener: OnConflictDecisionMadeListener? = null
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+
+        getArguments(savedInstanceState)
+
+        val upload = uploadsStorageManager?.getUploadById(conflictUploadId)
+        if (upload != null) {
+            localBehaviour = upload.localAction
+        }
+
+        // new file was modified locally in file system
+        newFile = file
+        setupOnConflictDecisionMadeListener(upload)
+    }
+
+    private fun getArguments(savedInstanceState: Bundle?) {
+        if (savedInstanceState != null) {
+            conflictUploadId = savedInstanceState.getLong(EXTRA_CONFLICT_UPLOAD_ID)
+            existingFile = savedInstanceState.getParcelableArgument(EXTRA_EXISTING_FILE, OCFile::class.java)
+            localBehaviour = savedInstanceState.getInt(EXTRA_LOCAL_BEHAVIOUR)
+        } else {
+            conflictUploadId = intent.getLongExtra(EXTRA_CONFLICT_UPLOAD_ID, -1)
+            existingFile = intent.getParcelableExtra(EXTRA_EXISTING_FILE)
+            localBehaviour = intent.getIntExtra(EXTRA_LOCAL_BEHAVIOUR, localBehaviour)
+        }
+    }
+
+    private fun setupOnConflictDecisionMadeListener(upload: OCUpload?) {
+        listener = OnConflictDecisionMadeListener { decision: Decision? ->
+            val file = newFile // local file got changed, so either upload it or replace it again by server
+            // version
+            val user = user.orElseThrow { RuntimeException() }
+            when (decision) {
+                Decision.CANCEL -> {}
+                Decision.KEEP_LOCAL -> {
+                    FileUploader.uploadUpdateFile(
+                        baseContext,
+                        user,
+                        file,
+                        localBehaviour,
+                        NameCollisionPolicy.OVERWRITE
+                    )
+                    uploadsStorageManager!!.removeUpload(upload)
+                }
+
+                Decision.KEEP_BOTH -> {
+                    FileUploader.uploadUpdateFile(
+                        baseContext,
+                        user,
+                        file,
+                        localBehaviour,
+                        NameCollisionPolicy.RENAME
+                    )
+                    uploadsStorageManager!!.removeUpload(upload)
+                }
+
+                Decision.KEEP_SERVER -> if (!shouldDeleteLocal()) {
+                    // Overwrite local file
+                    val intent = Intent(baseContext, FileDownloader::class.java)
+                    intent.putExtra(FileDownloader.EXTRA_USER, getUser().orElseThrow { RuntimeException() })
+                    intent.putExtra(FileDownloader.EXTRA_FILE, file)
+                    intent.putExtra(EXTRA_CONFLICT_UPLOAD_ID, conflictUploadId)
+                    startService(intent)
+                } else {
+                    uploadsStorageManager!!.removeUpload(upload)
+                }
+
+                else -> {}
+            }
+            finish()
+        }
+    }
+
+    override fun onSaveInstanceState(outState: Bundle) {
+        super.onSaveInstanceState(outState)
+        outState.putLong(EXTRA_CONFLICT_UPLOAD_ID, conflictUploadId)
+        outState.putParcelable(EXTRA_EXISTING_FILE, existingFile)
+        outState.putInt(EXTRA_LOCAL_BEHAVIOUR, localBehaviour)
+    }
+
+    override fun conflictDecisionMade(decision: Decision) {
+        listener?.conflictDecisionMade(decision)
+    }
+
+    override fun onStart() {
+        super.onStart()
+        if (account == null) {
+            finish()
+            return
+        }
+        if (newFile == null) {
+            Log_OC.e(TAG, "No file received")
+            finish()
+            return
+        }
+        if (existingFile == null) {
+            // fetch info of existing file from server
+            val operation = ReadFileRemoteOperation(newFile!!.remotePath)
+
+            @Suppress("TooGenericExceptionCaught")
+            Thread {
+                try {
+                    val result = operation.execute(account, this)
+                    if (result.isSuccess) {
+                        existingFile = FileStorageUtils.fillOCFile(result.data[0] as RemoteFile)
+                        existingFile?.lastSyncDateForProperties = System.currentTimeMillis()
+                        startDialog()
+                    } else {
+                        Log_OC.e(TAG, "ReadFileRemoteOp returned failure with code: " + result.httpCode)
+                        showErrorAndFinish()
+                    }
+                } catch (e: Exception) {
+                    Log_OC.e(TAG, "Error when trying to fetch remote file", e)
+                    showErrorAndFinish()
+                }
+            }.start()
+        } else {
+            startDialog()
+        }
+    }
+
+    private fun startDialog() {
+        val userOptional = user
+        if (!userOptional.isPresent) {
+            Log_OC.e(TAG, "User not present")
+            showErrorAndFinish()
+        }
+
+        // Check whether the file is contained in the current Account
+        val prev = supportFragmentManager.findFragmentByTag("conflictDialog")
+        val fragmentTransaction = supportFragmentManager.beginTransaction()
+        if (prev != null) {
+            fragmentTransaction.remove(prev)
+        }
+        if (existingFile != null && storageManager.fileExists(newFile!!.remotePath)) {
+            val dialog = ConflictsResolveDialog.newInstance(
+                existingFile,
+                newFile,
+                userOptional.get()
+            )
+            dialog.show(fragmentTransaction, "conflictDialog")
+        } else {
+            // Account was changed to a different one - just finish
+            Log_OC.e(TAG, "Account was changed, finishing")
+            showErrorAndFinish()
+        }
+    }
+
+    private fun showErrorAndFinish() {
+        runOnUiThread { Toast.makeText(this, R.string.conflict_dialog_error, Toast.LENGTH_LONG).show() }
+        finish()
+    }
+
+    /**
+     * @return whether the local version of the files is to be deleted.
+     */
+    private fun shouldDeleteLocal(): Boolean {
+        return localBehaviour == FileUploader.LOCAL_BEHAVIOUR_DELETE
+    }
+
+    companion object {
+        /**
+         * A nullable upload entry that must be removed when and if the conflict is resolved.
+         */
+        const val EXTRA_CONFLICT_UPLOAD_ID = "CONFLICT_UPLOAD_ID"
+
+        /**
+         * Specify the upload local behaviour when there is no CONFLICT_UPLOAD.
+         */
+        const val EXTRA_LOCAL_BEHAVIOUR = "LOCAL_BEHAVIOUR"
+        const val EXTRA_EXISTING_FILE = "EXISTING_FILE"
+        private val TAG = ConflictsResolveActivity::class.java.simpleName
+
+        @JvmStatic
+        fun createIntent(
+            file: OCFile?,
+            user: User?,
+            conflictUploadId: Long,
+            flag: Int?,
+            context: Context?
+        ): Intent {
+            val intent = Intent(context, ConflictsResolveActivity::class.java)
+            if (flag != null) {
+                intent.flags = intent.flags or flag
+            }
+            intent.putExtra(EXTRA_FILE, file)
+            intent.putExtra(EXTRA_USER, user)
+            intent.putExtra(EXTRA_CONFLICT_UPLOAD_ID, conflictUploadId)
+            return intent
+        }
+    }
+}

+ 10 - 16
app/src/main/java/com/owncloud/android/ui/activity/CopyToClipboardActivity.java → app/src/main/java/com/owncloud/android/ui/activity/CopyToClipboardActivity.kt

@@ -18,26 +18,20 @@
  *   You should have received a copy of the GNU General Public License
  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
+package com.owncloud.android.ui.activity
 
-package com.owncloud.android.ui.activity;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-
-import com.owncloud.android.utils.ClipboardUtil;
+import android.app.Activity
+import android.content.Intent
+import android.os.Bundle
+import com.owncloud.android.utils.ClipboardUtil
 
 /**
  * Activity copying the text of the received Intent into the system clipboard.
  */
-public class CopyToClipboardActivity extends Activity {
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        ClipboardUtil.copyToClipboard(this, getIntent().getCharSequenceExtra(Intent.EXTRA_TEXT).toString());
-
-        finish();
+class CopyToClipboardActivity : Activity() {
+    public override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        ClipboardUtil.copyToClipboard(this, intent.getCharSequenceExtra(Intent.EXTRA_TEXT).toString())
+        finish()
     }
 }

+ 4 - 5
app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java

@@ -479,7 +479,6 @@ public abstract class DrawerActivity extends ToolbarActivity
         unsetAllDrawerMenuItems();
     }
 
-
     private void onNavigationItemClicked(final MenuItem menuItem) {
         setDrawerMenuItemChecked(menuItem.getItemId());
 
@@ -506,7 +505,7 @@ public abstract class DrawerActivity extends ToolbarActivity
             handleSearchEvents(new SearchEvent("", SearchRemoteOperation.SearchType.FAVORITE_SEARCH),
                                menuItem.getItemId());
         } else if (itemId == R.id.nav_gallery) {
-            startPhotoSearch(menuItem);
+            startPhotoSearch(menuItem.getItemId());
         } else if (itemId == R.id.nav_on_device) {
             EventBus.getDefault().post(new ChangeMenuEvent());
             showFiles(true);
@@ -527,7 +526,7 @@ public abstract class DrawerActivity extends ToolbarActivity
             menuItem.setChecked(false);
             final Optional<User> optionalUser = getUser();
             if (optionalUser.isPresent()) {
-                UserInfoActivity.openAccountRemovalConfirmationDialog(optionalUser.get(), getSupportFragmentManager());
+                UserInfoActivity.openAccountRemovalDialog(optionalUser.get(), getSupportFragmentManager());
             }
         } else if (itemId == R.id.nav_shared) {
             startSharedSearch(menuItem);
@@ -598,11 +597,11 @@ public abstract class DrawerActivity extends ToolbarActivity
         launchActivityForSearch(searchEvent, menuItem.getItemId());
     }
 
-    private void startPhotoSearch(MenuItem menuItem) {
+    public void startPhotoSearch(int id) {
         SearchEvent searchEvent = new SearchEvent("image/%", SearchRemoteOperation.SearchType.PHOTO_SEARCH);
         MainApp.showOnlyFilesOnDevice(false);
 
-        launchActivityForSearch(searchEvent, menuItem.getItemId());
+        launchActivityForSearch(searchEvent, id);
     }
 
     private void handleSearchEvents(SearchEvent searchEvent, int menuItemId) {

+ 4 - 5
app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java

@@ -58,7 +58,7 @@ import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.services.OperationsService;
 import com.owncloud.android.ui.adapter.UserListAdapter;
 import com.owncloud.android.ui.adapter.UserListItem;
-import com.owncloud.android.ui.dialog.AccountRemovalConfirmationDialog;
+import com.owncloud.android.ui.dialog.AccountRemovalDialog;
 import com.owncloud.android.ui.events.AccountRemovedEvent;
 import com.owncloud.android.ui.helpers.FileOperationsHelper;
 
@@ -470,9 +470,8 @@ public class ManageAccountsActivity extends FileActivity implements UserListAdap
         }
     }
 
-    public static void openAccountRemovalConfirmationDialog(User user, FragmentManager fragmentManager) {
-        AccountRemovalConfirmationDialog dialog =
-            AccountRemovalConfirmationDialog.newInstance(user);
+    public static void openAccountRemovalDialog(User user, FragmentManager fragmentManager) {
+        AccountRemovalDialog dialog = AccountRemovalDialog.newInstance(user);
         dialog.show(fragmentManager, "dialog");
     }
 
@@ -509,7 +508,7 @@ public class ManageAccountsActivity extends FileActivity implements UserListAdap
                 if (itemId == R.id.action_open_account) {
                     accountClicked(user.hashCode());
                 } else if (itemId == R.id.action_delete_account) {
-                    openAccountRemovalConfirmationDialog(user, getSupportFragmentManager());
+                    openAccountRemovalDialog(user, getSupportFragmentManager());
                 } else {
                     openAccount(user);
                 }

+ 4 - 4
app/src/main/java/com/owncloud/android/ui/activity/UserInfoActivity.java

@@ -56,7 +56,7 @@ import com.owncloud.android.lib.common.accounts.AccountUtils;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult;
 import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.lib.resources.users.GetUserInfoRemoteOperation;
-import com.owncloud.android.ui.dialog.AccountRemovalConfirmationDialog;
+import com.owncloud.android.ui.dialog.AccountRemovalDialog;
 import com.owncloud.android.ui.events.TokenPushEvent;
 import com.owncloud.android.utils.DisplayUtils;
 import com.owncloud.android.utils.PushUtils;
@@ -173,7 +173,7 @@ public class UserInfoActivity extends DrawerActivity implements Injectable {
         } else if (itemId == R.id.action_open_account) {
             accountClicked(user.hashCode());
         } else if (itemId == R.id.action_delete_account) {
-            openAccountRemovalConfirmationDialog(user, getSupportFragmentManager());
+            openAccountRemovalDialog(user, getSupportFragmentManager());
         } else {
             retval = super.onOptionsItemSelected(item);
         }
@@ -302,8 +302,8 @@ public class UserInfoActivity extends DrawerActivity implements Injectable {
         }
     }
 
-    public static void openAccountRemovalConfirmationDialog(User user, FragmentManager fragmentManager) {
-        AccountRemovalConfirmationDialog dialog = AccountRemovalConfirmationDialog.newInstance(user);
+    public static void openAccountRemovalDialog(User user, FragmentManager fragmentManager) {
+        AccountRemovalDialog dialog = AccountRemovalDialog.newInstance(user);
         dialog.show(fragmentManager, "dialog");
     }
 

+ 0 - 105
app/src/main/java/com/owncloud/android/ui/dialog/AccountRemovalConfirmationDialog.kt

@@ -1,105 +0,0 @@
-/*
- * Nextcloud Android client application
- *
- * @author Tobias Kaminsky
- * Copyright (C) 2020 Tobias Kaminsky
- * Copyright (C) 2020 Nextcloud GmbH
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
-package com.owncloud.android.ui.dialog
-
-import android.app.Dialog
-import android.content.DialogInterface
-import android.os.Build
-import android.os.Bundle
-import androidx.appcompat.app.AlertDialog
-import androidx.fragment.app.DialogFragment
-import com.google.android.material.button.MaterialButton
-import com.google.android.material.dialog.MaterialAlertDialogBuilder
-import com.nextcloud.client.account.User
-import com.nextcloud.client.di.Injectable
-import com.nextcloud.client.jobs.BackgroundJobManager
-import com.owncloud.android.R
-import com.owncloud.android.utils.theme.ViewThemeUtils
-import javax.inject.Inject
-
-class AccountRemovalConfirmationDialog : DialogFragment(), Injectable {
-    @JvmField
-    @Inject
-    var backgroundJobManager: BackgroundJobManager? = null
-
-    @JvmField
-    @Inject
-    var viewThemeUtils: ViewThemeUtils? = null
-
-    private var user: User? = null
-
-    override fun onCreate(savedInstanceState: Bundle?) {
-        super.onCreate(savedInstanceState)
-
-        user = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
-            requireArguments().getParcelable(KEY_USER, User::class.java)
-        } else {
-            @Suppress("DEPRECATION")
-            requireArguments().getParcelable(KEY_USER)
-        }
-    }
-
-    override fun onStart() {
-        super.onStart()
-
-        val alertDialog = dialog as AlertDialog?
-
-        if (alertDialog != null) {
-            val positiveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE) as MaterialButton
-            viewThemeUtils?.material?.colorMaterialButtonPrimaryTonal(positiveButton)
-
-            val negativeButton = alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE) as MaterialButton
-            viewThemeUtils?.material?.colorMaterialButtonPrimaryBorderless(negativeButton)
-        }
-    }
-
-    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
-        val builder = MaterialAlertDialogBuilder(requireActivity())
-            .setTitle(R.string.delete_account)
-            .setMessage(resources.getString(R.string.delete_account_warning, user!!.accountName))
-            .setIcon(R.drawable.ic_warning)
-            .setPositiveButton(R.string.common_ok) { _: DialogInterface?, _: Int ->
-                backgroundJobManager?.startAccountRemovalJob(
-                    user!!.accountName,
-                    false
-                )
-            }
-            .setNegativeButton(R.string.common_cancel, null)
-
-        viewThemeUtils?.dialog?.colorMaterialAlertDialogBackground(requireActivity(), builder)
-
-        return builder.create()
-    }
-
-    companion object {
-
-        private const val KEY_USER = "USER"
-
-        @JvmStatic
-        fun newInstance(user: User?): AccountRemovalConfirmationDialog {
-            val bundle = Bundle()
-            bundle.putParcelable(KEY_USER, user)
-            val dialog = AccountRemovalConfirmationDialog()
-            dialog.arguments = bundle
-            return dialog
-        }
-    }
-}

+ 194 - 0
app/src/main/java/com/owncloud/android/ui/dialog/AccountRemovalDialog.kt

@@ -0,0 +1,194 @@
+/*
+ * Nextcloud Android client application
+ *
+ * @author ZetaTom
+ * @author Tobias Kaminsky
+ * Copyright (C) 2023 ZetaTom
+ * Copyright (C) 2020 Tobias Kaminsky
+ * Copyright (C) 2020 Nextcloud GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package com.owncloud.android.ui.dialog
+
+import android.app.Dialog
+import android.graphics.drawable.Drawable
+import android.os.Bundle
+import android.view.View
+import androidx.appcompat.app.AlertDialog
+import androidx.fragment.app.DialogFragment
+import com.google.android.material.button.MaterialButton
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import com.nextcloud.client.account.User
+import com.nextcloud.client.account.UserAccountManager
+import com.nextcloud.client.di.Injectable
+import com.nextcloud.client.jobs.BackgroundJobManager
+import com.nextcloud.utils.extensions.getParcelableArgument
+import com.owncloud.android.R
+import com.owncloud.android.databinding.AccountRemovalDialogBinding
+import com.owncloud.android.datamodel.FileDataStorageManager
+import com.owncloud.android.utils.DisplayUtils
+import com.owncloud.android.utils.DisplayUtils.AvatarGenerationListener
+import com.owncloud.android.utils.theme.ViewThemeUtils
+import javax.inject.Inject
+
+class AccountRemovalDialog : DialogFragment(), AvatarGenerationListener, Injectable {
+
+    @Inject
+    lateinit var backgroundJobManager: BackgroundJobManager
+
+    @Inject
+    lateinit var viewThemeUtils: ViewThemeUtils
+
+    private var user: User? = null
+    private lateinit var alertDialog: AlertDialog
+    private var _binding: AccountRemovalDialogBinding? = null
+    private val binding get() = _binding!!
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        user = requireArguments().getParcelableArgument(KEY_USER, User::class.java)
+    }
+
+    override fun onStart() {
+        super.onStart()
+
+        // disable positive button and apply theming
+        alertDialog = dialog as AlertDialog
+        alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = false
+
+        viewThemeUtils.platform.themeRadioButton(binding.radioLocalRemove)
+        viewThemeUtils.platform.themeRadioButton(binding.radioRequestDeletion)
+        viewThemeUtils.material.colorMaterialButtonPrimaryTonal(
+            alertDialog.getButton(AlertDialog.BUTTON_POSITIVE) as MaterialButton
+        )
+        viewThemeUtils.material.colorMaterialButtonPrimaryBorderless(
+            alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE) as MaterialButton
+        )
+
+        binding.userName.text = UserAccountManager.getDisplayName(user)
+        binding.account.text = user?.let { DisplayUtils.convertIdn(it.accountName, false) }
+    }
+
+    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+        _binding = AccountRemovalDialogBinding.inflate(layoutInflater)
+
+        // start avatar generation
+        setAvatar()
+
+        // hide second option when plug-in isn't installed
+        if (hasDropAccount()) {
+            binding.requestDeletion.visibility = View.VISIBLE
+        }
+
+        val builder =
+            MaterialAlertDialogBuilder(requireActivity())
+                .setTitle(R.string.delete_account)
+                .setView(binding.root)
+                .setNegativeButton(R.string.common_cancel) { _, _ -> }
+                .setPositiveButton(R.string.delete_account) { _, _ -> removeAccount() }
+
+        // allow selection by clicking on list element
+        binding.localRemove.setOnClickListener {
+            binding.radioLocalRemove.performClick()
+        }
+        binding.requestDeletion.setOnClickListener {
+            binding.radioRequestDeletion.performClick()
+        }
+
+        // set listeners for custom radio button list
+        binding.radioLocalRemove.setOnClickListener {
+            binding.radioRequestDeletion.isChecked = false
+            alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).apply {
+                text = getText(R.string.delete_account)
+                isEnabled = true
+            }
+        }
+        binding.radioRequestDeletion.setOnClickListener {
+            binding.radioLocalRemove.isChecked = false
+            alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).apply {
+                text = getString(R.string.request_account_deletion_button)
+                isEnabled = true
+            }
+        }
+
+        viewThemeUtils.dialog.colorMaterialAlertDialogBackground(requireActivity(), builder)
+
+        return builder.create()
+    }
+
+    /**
+     * Get value of `drop-account` capability.
+     */
+    private fun hasDropAccount(): Boolean {
+        val capability = FileDataStorageManager(user, context?.contentResolver).getCapability(user)
+        return capability.dropAccount.isTrue
+    }
+
+    /**
+     * Start removal of account. Depending on which option is checked, either a browser will open to request deletion,
+     * or the local account will be removed immediately.
+     */
+    private fun removeAccount() {
+        user?.let { user ->
+            if (binding.radioRequestDeletion.isChecked) {
+                DisplayUtils.startLinkIntent(activity, user.server.uri.toString() + DROP_ACCOUNT_URI)
+            } else {
+                backgroundJobManager.startAccountRemovalJob(user.accountName, false)
+            }
+        }
+    }
+
+    /**
+     * Start avatar generation.
+     */
+    private fun setAvatar() {
+        try {
+            val imageView = binding.userIcon
+            imageView.tag = user!!.accountName
+            DisplayUtils.setAvatar(
+                user!!,
+                this,
+                resources.getDimension(R.dimen.list_item_avatar_icon_radius),
+                resources,
+                imageView,
+                context
+            )
+        } catch (_: Exception) {
+        }
+    }
+
+    override fun avatarGenerated(avatarDrawable: Drawable?, callContext: Any?) {
+        avatarDrawable?.let {
+            binding.userIcon.setImageDrawable(it)
+        }
+    }
+
+    override fun shouldCallGeneratedCallback(tag: String?, callContext: Any?): Boolean {
+        return binding.userIcon.tag == tag
+    }
+
+    companion object {
+        private const val KEY_USER = "USER"
+        private const val DROP_ACCOUNT_URI = "/settings/user/drop_account"
+
+        @JvmStatic
+        fun newInstance(user: User) = AccountRemovalDialog().apply {
+            arguments = Bundle().apply {
+                putParcelable(KEY_USER, user)
+            }
+        }
+    }
+}

+ 9 - 12
app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java

@@ -91,7 +91,6 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
 
     private static final String ARG_FILE = "FILE";
     private static final String ARG_USER = "USER";
-    public static final int PERMISSION_EDITING_ALLOWED = 17;
 
     private OCFile file;
     private User user;
@@ -128,8 +127,8 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
         } else {
             Bundle arguments = getArguments();
             if (arguments != null) {
-                file = getArguments().getParcelable(ARG_FILE);
-                user = getArguments().getParcelable(ARG_USER);
+                file = arguments.getParcelable(ARG_FILE);
+                user = arguments.getParcelable(ARG_USER);
             }
         }
 
@@ -159,12 +158,11 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
     @Override
     public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
         binding = FileDetailsSharingFragmentBinding.inflate(inflater, container, false);
-        View view = binding.getRoot();
 
         fileOperationsHelper = fileActivity.getFileOperationsHelper();
         fileDataStorageManager = fileActivity.getStorageManager();
 
-        AccountManager accountManager = AccountManager.get(getContext());
+        AccountManager accountManager = AccountManager.get(requireContext());
         String userId = accountManager.getUserData(user.toPlatformAccount(),
                                                    com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_USER_ID);
 
@@ -175,13 +173,14 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
                                                             user,
                                                             viewThemeUtils,
                                                             file.isEncrypted()));
-        binding.sharesList.setLayoutManager(new LinearLayoutManager(getContext()));
+
+        binding.sharesList.setLayoutManager(new LinearLayoutManager(requireContext()));
 
         binding.pickContactEmailBtn.setOnClickListener(v -> checkContactPermission());
 
         setupView();
 
-        return view;
+        return binding.getRoot();
     }
 
     @Override
@@ -229,9 +228,7 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
     private void disableSearchView(View view) {
         view.setEnabled(false);
 
-        if (view instanceof ViewGroup) {
-            ViewGroup viewGroup = (ViewGroup) view;
-
+        if (view instanceof ViewGroup viewGroup) {
             for (int i = 0; i < viewGroup.getChildCount(); i++) {
                 disableSearchView(viewGroup.getChildAt(i));
             }
@@ -315,7 +312,7 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
             if (TextUtils.isEmpty(share.getShareLink())) {
                 fileOperationsHelper.getFileWithLink(file, viewThemeUtils);
             } else {
-                ClipboardUtil.copyToClipboard(getActivity(), share.getShareLink());
+                ClipboardUtil.copyToClipboard(requireActivity(), share.getShareLink());
             }
         }
     }
@@ -555,7 +552,7 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
 
     @VisibleForTesting
     public void search(String query) {
-        SearchView searchView = getView().findViewById(R.id.searchView);
+        SearchView searchView = requireView().findViewById(R.id.searchView);
         searchView.setQuery(query, true);
     }
 

+ 1 - 1
app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt

@@ -545,7 +545,7 @@ class FileDetailsSharingProcessFragment :
         )
         // copy the share link if available
         if (!TextUtils.isEmpty(share?.shareLink)) {
-            ClipboardUtil.copyToClipboard(activity, share?.shareLink)
+            ClipboardUtil.copyToClipboard(requireActivity(), share?.shareLink)
         }
     }
 

+ 32 - 6
app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragment.java

@@ -23,7 +23,10 @@
 
 package com.owncloud.android.ui.fragment;
 
+import android.content.BroadcastReceiver;
+import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.res.Configuration;
 import android.os.AsyncTask;
 import android.os.Bundle;
@@ -54,6 +57,7 @@ import javax.inject.Inject;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.fragment.app.FragmentActivity;
+import androidx.localbroadcastmanager.content.LocalBroadcastManager;
 import androidx.recyclerview.widget.GridLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
 
@@ -64,6 +68,8 @@ public class GalleryFragment extends OCFileListFragment implements GalleryFragme
     private static final int MAX_ITEMS_PER_ROW = 10;
     private static final String FRAGMENT_TAG_BOTTOM_SHEET = "data";
 
+    public static final String REFRESH_SEARCH_EVENT_RECEIVER = "refreshSearchEventReceiver";
+
     private boolean photoSearchQueryRunning = false;
     private AsyncTask<Void, Void, GallerySearchTask.Result> photoSearchTask;
     private long endDate;
@@ -103,6 +109,28 @@ public class GalleryFragment extends OCFileListFragment implements GalleryFragme
         } else {
             columnSize = maxColumnSizePortrait;
         }
+
+        registerRefreshSearchEventReceiver();
+    }
+
+    private void registerRefreshSearchEventReceiver() {
+        IntentFilter filter = new IntentFilter(REFRESH_SEARCH_EVENT_RECEIVER);
+        LocalBroadcastManager.getInstance(requireContext()).registerReceiver(refreshSearchEventReceiver, filter);
+    }
+
+    private final BroadcastReceiver refreshSearchEventReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (getActivity() instanceof FileDisplayActivity fileDisplayActivity) {
+                fileDisplayActivity.startPhotoSearch(R.id.nav_gallery);
+            }
+        }
+    };
+
+    @Override
+    public void onDestroyView() {
+        LocalBroadcastManager.getInstance(requireContext()).unregisterReceiver(refreshSearchEventReceiver);
+        super.onDestroyView();
     }
 
     @Override
@@ -200,10 +228,9 @@ public class GalleryFragment extends OCFileListFragment implements GalleryFragme
     @Override
     public void onResume() {
         super.onResume();
+
         setLoading(this.isPhotoSearchQueryRunning());
-        final FragmentActivity activity = getActivity();
-        if (activity instanceof FileDisplayActivity) {
-            FileDisplayActivity fileDisplayActivity = ((FileDisplayActivity) activity);
+        if (getActivity() instanceof FileDisplayActivity fileDisplayActivity) {
             fileDisplayActivity.updateActionBarTitleAndHomeButtonByString(getString(R.string.drawer_item_gallery));
             fileDisplayActivity.setMainFabVisible(false);
         }
@@ -247,7 +274,7 @@ public class GalleryFragment extends OCFileListFragment implements GalleryFragme
             setEmptyListMessage(SearchType.GALLERY_SEARCH);
         }
 
-        if(!emptySearch) {
+        if (!emptySearch) {
             this.showAllGalleryItems();
         }
 
@@ -317,8 +344,7 @@ public class GalleryFragment extends OCFileListFragment implements GalleryFragme
     }
 
     private void loadMoreWhenEndReached(@NonNull RecyclerView recyclerView, int dy) {
-        if (recyclerView.getLayoutManager() instanceof GridLayoutManager) {
-            GridLayoutManager gridLayoutManager = (GridLayoutManager) recyclerView.getLayoutManager();
+        if (recyclerView.getLayoutManager() instanceof GridLayoutManager gridLayoutManager) {
 
             // scroll down
             if (dy > 0 && !this.isPhotoSearchQueryRunning()) {

+ 28 - 22
app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java

@@ -57,6 +57,7 @@ import com.owncloud.android.operations.SynchronizeFileOperation;
 import com.owncloud.android.ui.activity.FileActivity;
 import com.owncloud.android.ui.activity.FileDisplayActivity;
 import com.owncloud.android.ui.fragment.FileFragment;
+import com.owncloud.android.ui.fragment.GalleryFragment;
 import com.owncloud.android.ui.fragment.OCFileListFragment;
 import com.owncloud.android.utils.MimeTypeUtil;
 
@@ -186,6 +187,33 @@ public class PreviewImageActivity extends FileActivity implements
         }
     }
 
+    @Override
+    public void onBackPressed() {
+        sendRefreshSearchEventBroadcast();
+        super.onBackPressed();
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        if (item.getItemId() == android.R.id.home) {
+            sendRefreshSearchEventBroadcast();
+
+            if (isDrawerOpen()) {
+                closeDrawer();
+            } else {
+                backToDisplayActivity();
+            }
+            return true;
+        } else {
+            return onOptionsItemSelected(item);
+        }
+    }
+
+    private void sendRefreshSearchEventBroadcast() {
+        Intent intent = new Intent(GalleryFragment.REFRESH_SEARCH_EVENT_RECEIVER);
+        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
+    }
+
     @Override
     public void onStart() {
         super.onStart();
@@ -307,28 +335,6 @@ public class PreviewImageActivity extends FileActivity implements
         super.onDestroy();
     }
 
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        boolean returnValue = false;
-
-        switch(item.getItemId()){
-        case android.R.id.home:
-            if (isDrawerOpen()) {
-                closeDrawer();
-            } else {
-                backToDisplayActivity();
-            }
-            returnValue = true;
-            break;
-        default:
-        	returnValue = super.onOptionsItemSelected(item);
-            break;
-        }
-
-        return returnValue;
-    }
-
-
     @Override
     protected void onResume() {
         super.onResume();

+ 2 - 0
app/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.java

@@ -412,6 +412,8 @@ public class PreviewImageFragment extends FileFragment implements Injectable {
             seeDetails();
         } else if (itemId == R.id.action_download_file || itemId == R.id.action_sync_file) {
             containerActivity.getFileOperationsHelper().syncFile(getFile());
+        }else if(itemId == R.id.action_cancel_sync){
+            containerActivity.getFileOperationsHelper().cancelTransference(getFile());
         } else if (itemId == R.id.action_set_as_wallpaper) {
             containerActivity.getFileOperationsHelper().setPictureAs(getFile(), getImageView());
         } else if (itemId == R.id.action_export_file) {

+ 2 - 0
app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java

@@ -450,6 +450,8 @@ public class PreviewMediaFragment extends FileFragment implements OnTouchListene
             seeDetails();
         } else if (itemId == R.id.action_sync_file) {
             containerActivity.getFileOperationsHelper().syncFile(getFile());
+        } else if (itemId == R.id.action_cancel_sync) {
+            containerActivity.getFileOperationsHelper().cancelTransference(getFile());
         } else if (itemId == R.id.action_stream_media) {
             containerActivity.getFileOperationsHelper().streamMediaFile(getFile());
         } else if (itemId == R.id.action_export_file) {

+ 2 - 0
app/src/main/java/com/owncloud/android/ui/preview/PreviewTextFileFragment.java

@@ -330,6 +330,8 @@ public class PreviewTextFileFragment extends PreviewTextFragment {
             seeDetails();
         } else if (itemId == R.id.action_sync_file) {
             containerActivity.getFileOperationsHelper().syncFile(getFile());
+        } else if(itemId == R.id.action_cancel_sync){
+            containerActivity.getFileOperationsHelper().cancelTransference(getFile());
         } else if (itemId == R.id.action_edit) {
             containerActivity.getFileOperationsHelper().openFileWithTextEditor(getFile(), getContext());
         }

+ 28 - 33
app/src/main/java/com/owncloud/android/utils/ClipboardUtil.java → app/src/main/java/com/owncloud/android/utils/ClipboardUtil.kt

@@ -17,51 +17,46 @@
  * You should have received a copy of the GNU Affero General Public
  * License along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
+package com.owncloud.android.utils
 
-package com.owncloud.android.utils;
-
-import android.app.Activity;
-import android.content.ClipData;
-import android.content.ClipboardManager;
-import android.content.Context;
-import android.text.TextUtils;
-import android.widget.Toast;
-
-import com.owncloud.android.R;
-import com.owncloud.android.lib.common.utils.Log_OC;
+import android.app.Activity
+import android.content.ClipData
+import android.content.ClipboardManager
+import android.content.Context
+import android.text.TextUtils
+import android.widget.Toast
+import com.owncloud.android.R
+import com.owncloud.android.lib.common.utils.Log_OC
 
 /**
  * Helper implementation to copy a string into the system clipboard.
  */
-public final class ClipboardUtil {
-    private static final String TAG = ClipboardUtil.class.getName();
-
-    private ClipboardUtil() {
-    }
+object ClipboardUtil {
+    private val TAG = ClipboardUtil::class.java.name
 
-    public static void copyToClipboard(Activity activity, String text) {
-        copyToClipboard(activity, text, true);
-    }
-
-    public static void copyToClipboard(Activity activity, String text, boolean showToast) {
+    @JvmStatic
+    @JvmOverloads
+    @Suppress("TooGenericExceptionCaught")
+    fun copyToClipboard(activity: Activity, text: String?, showToast: Boolean = true) {
         if (!TextUtils.isEmpty(text)) {
             try {
-                ClipData clip = ClipData.newPlainText(
-                        activity.getString(
-                                R.string.clipboard_label, activity.getString(R.string.app_name)),
-                        text
-                );
-                ((ClipboardManager) activity.getSystemService(Context.CLIPBOARD_SERVICE)).setPrimaryClip(clip);
-
+                val clip = ClipData.newPlainText(
+                    activity.getString(
+                        R.string.clipboard_label,
+                        activity.getString(R.string.app_name)
+                    ),
+                    text
+                )
+                (activity.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager).setPrimaryClip(clip)
                 if (showToast) {
-                    Toast.makeText(activity, R.string.clipboard_text_copied, Toast.LENGTH_SHORT).show();
+                    Toast.makeText(activity, R.string.clipboard_text_copied, Toast.LENGTH_SHORT).show()
                 }
-            } catch (Exception e) {
-                Toast.makeText(activity, R.string.clipboard_unexpected_error, Toast.LENGTH_SHORT).show();
-                Log_OC.e(TAG, "Exception caught while copying to clipboard", e);
+            } catch (e: Exception) {
+                Toast.makeText(activity, R.string.clipboard_unexpected_error, Toast.LENGTH_SHORT).show()
+                Log_OC.e(TAG, "Exception caught while copying to clipboard", e)
             }
         } else {
-            Toast.makeText(activity, R.string.clipboard_no_text_to_copy, Toast.LENGTH_SHORT).show();
+            Toast.makeText(activity, R.string.clipboard_no_text_to_copy, Toast.LENGTH_SHORT).show()
         }
     }
 }

+ 3 - 0
app/src/main/java/com/owncloud/android/utils/ErrorMessageAdapter.java

@@ -437,6 +437,9 @@ public final class ErrorMessageAdapter {
             } else if (result.getCode() == ResultCode.ACCOUNT_NOT_THE_SAME) {
                 message = res.getString(R.string.auth_account_not_the_same);
 
+            } else if (result.getCode() == ResultCode.QUOTA_EXCEEDED) {
+                message = res.getString(R.string.upload_quota_exceeded);
+
             }
 
             else if (!TextUtils.isEmpty(result.getHttpPhrase())) {

+ 13 - 0
app/src/main/java/com/owncloud/android/utils/FilesUploadHelper.kt

@@ -70,6 +70,19 @@ class FilesUploadHelper {
         backgroundJobManager.startFilesUploadJob(user)
     }
 
+    fun cancelFileUpload(remotePath: String, user: User) {
+        // need to update now table in mUploadsStorageManager,
+        // since the operation will not get to be run by FileUploader#uploadFile
+        uploadsStorageManager.removeUpload(user.accountName, remotePath)
+
+        restartUploadJob(user)
+    }
+
+    fun restartUploadJob(user: User) {
+        backgroundJobManager.cancelFilesUploadJob(user)
+        backgroundJobManager.startFilesUploadJob(user)
+    }
+
     fun uploadUpdatedFile(
         user: User,
         existingFiles: Array<OCFile>,

+ 154 - 0
app/src/main/res/layout/account_removal_dialog.xml

@@ -0,0 +1,154 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Nextcloud Android client application
+
+ @author ZetaTom
+ Copyright (C) 2023 ZetaTom
+ Copyright (C) 2023 Nextcloud GmbH
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center_vertical"
+        android:orientation="horizontal"
+        android:padding="12dp"
+        android:paddingHorizontal="24dp">
+
+        <ImageView
+            android:id="@+id/user_icon"
+            android:layout_width="@dimen/user_icon_size"
+            android:layout_height="@dimen/user_icon_size"
+            android:layout_margin="6dp"
+            android:contentDescription="@string/avatar"
+            android:src="@drawable/ic_user" />
+
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="6dp"
+            android:orientation="vertical">
+
+            <androidx.appcompat.widget.AppCompatTextView
+                android:id="@+id/user_name"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:ellipsize="middle"
+                android:textAppearance="@style/TextAppearance.Material3.LabelLarge"
+                tools:text="Alice Muster" />
+
+            <androidx.appcompat.widget.AppCompatTextView
+                android:id="@+id/account"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:ellipsize="middle"
+                tools:text="alice@cloud.nextcloud.com" />
+
+        </LinearLayout>
+
+    </LinearLayout>
+
+    <com.google.android.material.divider.MaterialDivider
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+
+    <LinearLayout
+        android:id="@+id/local_remove"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="?attr/selectableItemBackground"
+        android:clickable="true"
+        android:focusable="true"
+        android:gravity="center_vertical"
+        android:orientation="horizontal"
+        android:paddingHorizontal="24dp"
+        android:paddingVertical="8dp">
+
+        <androidx.appcompat.widget.AppCompatRadioButton
+            android:id="@+id/radio_local_remove"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            tools:checked="true" />
+
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+
+            <androidx.appcompat.widget.AppCompatTextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/remove_local_account"
+                android:textAppearance="@style/TextAppearance.Material3.LabelLarge" />
+
+            <androidx.appcompat.widget.AppCompatTextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/remove_local_account_details" />
+
+        </LinearLayout>
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/request_deletion"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="?attr/selectableItemBackground"
+        android:clickable="true"
+        android:focusable="true"
+        android:gravity="center_vertical"
+        android:orientation="horizontal"
+        android:paddingHorizontal="24dp"
+        android:paddingVertical="8dp"
+        android:visibility="gone"
+        tools:visibility="visible">
+
+        <androidx.appcompat.widget.AppCompatRadioButton
+            android:id="@+id/radio_request_deletion"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+
+            <androidx.appcompat.widget.AppCompatTextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/request_account_deletion"
+                android:textAppearance="@style/TextAppearance.Material3.LabelLarge" />
+
+            <androidx.appcompat.widget.AppCompatTextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/request_account_deletion_details" />
+
+        </LinearLayout>
+
+    </LinearLayout>
+
+    <com.google.android.material.divider.MaterialDivider
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+
+</LinearLayout>

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

@@ -160,6 +160,7 @@
     <string name="conflict_message_description">إذا قمت باختيار كلا الاصدارين, الملف المحلي سيحتوي على رقم ملحق باسم الملف.</string>
     <string name="conflict_server_file">ملف على الخادم</string>
     <string name="contact_backup_title">نسخ احتياطي لجهات الاتصال</string>
+    <string name="contact_no_permission">إذن الاتصال بالجهة لازم.</string>
     <string name="contactlist_item_icon">أيقونة المستخدمين المتواجدين في قائمة جهات الإتصال</string>
     <string name="contactlist_no_permission">لا يوجد إذن، لم يتم استيراد أي شيء</string>
     <string name="contacts">جهات الاتصال</string>
@@ -258,6 +259,7 @@
     <string name="ecosystem_apps_more">المزيد من تطبيقات نكست كلاود</string>
     <string name="ecosystem_apps_notes">ملاحظات Notes نيكست كلاود</string>
     <string name="ecosystem_apps_talk">تطبيق \"المحادثة\" talk من نكست كلاود</string>
+    <string name="email_pick_failed">تعذّر التقاط عنوان الإيميل.</string>
     <string name="encrypted">عيّنه كَمشفر</string>
     <string name="end_to_end_encryption_confirm_button">تنصيب التشفير</string>
     <string name="end_to_end_encryption_decrypting">جارِ فك التشفير …</string>
@@ -653,12 +655,17 @@
     <string name="remove_e2e">يُمكنك إلغاء التشفير المحلي لهذا العميل</string>
     <string name="remove_e2e_message">يُمكنك إلغاء التشفير المحلي لهذا العميل. هذا الملف المُشفّر سوف يبقى على الخادوم لكن لن تتم مزامنته مع هذا الحاسوب بعد الآن.</string>
     <string name="remove_fail_msg">فشلت عملية الحذف</string>
+    <string name="remove_local_account">إزالة الحساب المحلي</string>
+    <string name="remove_local_account_details">إزِل الحساب من الجهاز و احذُف كل الملفات المحلية</string>
     <string name="remove_notification_failed">فشل في إزالة الإخطار.</string>
     <string name="remove_push_notification">حذف</string>
     <string name="remove_success_msg">تم حذفه</string>
     <string name="rename_dialog_title">أدخل اسما جديداً</string>
     <string name="rename_local_fail_msg">تعذرت إعادة تسمية النسخة المحلية ، حاول استخدام اسم مختلف</string>
     <string name="rename_server_fail_msg">إعادة التسمية غير ممكنة ، الاسم مأخوذ بالفعل</string>
+    <string name="request_account_deletion">طلب حذف حساب</string>
+    <string name="request_account_deletion_button">طلب الإزالة</string>
+    <string name="request_account_deletion_details">طلب الإزالة الدائمة للحساب من قِبل مُزوّد الخدمة</string>
     <string name="reshare_not_allowed">لا يسمح بعملية إعادة المشاركة</string>
     <string name="resharing_is_not_allowed">لا يسمح بعملية إعادة المشاركة</string>
     <string name="resized_image_not_possible_download">لا توجد صورة بحجمها متاح. تنزيل الصورة الكاملة؟</string>
@@ -884,6 +891,7 @@
     <string name="upload_lock_failed">فشل قفّل المجلد</string>
     <string name="upload_old_android">التشفير ممكن فقط مع &gt;= Android 5.0</string>
     <string name="upload_query_move_foreign_files">يمنع وجود مساحة غير كافية نسخ الملفات المحددة إلى المجلد %1$s. هل ترغب في نقلهم إلى هناك بدلاً من ذلك؟</string>
+    <string name="upload_quota_exceeded">الحصة التخزينية تمّ استنفاذها</string>
     <string name="upload_scan_doc_upload">مسح مستند عبر الكاميرا</string>
     <string name="upload_sync_conflict">تعارض المزامنة ، يرجى حلها يدويًا</string>
     <string name="upload_unknown_error">خطأ غير معروف</string>

+ 11 - 1
app/src/main/res/values-b+en+001/strings.xml

@@ -18,6 +18,7 @@
     <string name="actionbar_copy">Copy</string>
     <string name="actionbar_mkdir">New folder</string>
     <string name="actionbar_move">Move</string>
+    <string name="actionbar_move_or_copy">Move or Copy</string>
     <string name="actionbar_open_with">Open with</string>
     <string name="actionbar_search">Search</string>
     <string name="actionbar_see_details">Details</string>
@@ -159,6 +160,7 @@
     <string name="conflict_message_description">If you select both versions, the local file will have a number appended to its name.</string>
     <string name="conflict_server_file">Server file</string>
     <string name="contact_backup_title">Contacts backup</string>
+    <string name="contact_no_permission">Contact permission is required.</string>
     <string name="contactlist_item_icon">User icon for contact list</string>
     <string name="contactlist_no_permission">No permission given, nothing imported.</string>
     <string name="contacts">Contacts</string>
@@ -257,6 +259,7 @@
     <string name="ecosystem_apps_more">More Nextcloud Apps</string>
     <string name="ecosystem_apps_notes">Nextcloud Notes</string>
     <string name="ecosystem_apps_talk">Nextcloud Talk</string>
+    <string name="email_pick_failed">Failed to pick email address.</string>
     <string name="encrypted">Set as encrypted</string>
     <string name="end_to_end_encryption_confirm_button">Set up encryption</string>
     <string name="end_to_end_encryption_decrypting">Decrypting…</string>
@@ -287,7 +290,7 @@
     <string name="error_report_issue_text">Report issue to tracker? (requires a GitHub account)</string>
     <string name="error_retrieving_file">Error retrieving file</string>
     <string name="error_retrieving_templates">Error retrieving templates</string>
-    <string name="error_showing_encryption_dialog">Error showing encryption setup dialog!</string>
+    <string name="error_showing_encryption_dialog">Error showing encryption setup dialogue!</string>
     <string name="error_starting_direct_camera_upload">Error starting camera</string>
     <string name="error_starting_doc_scan">Error starting document scan</string>
     <string name="etm_accounts">Accounts</string>
@@ -647,12 +650,17 @@
     <string name="remove_e2e">You can remove end-to-end encryption locally on this client</string>
     <string name="remove_e2e_message">You can remove end-to-end encryption locally on this client. The encrypted files will remain on server, but will not be synced to this computer any longer.</string>
     <string name="remove_fail_msg">Deletion failed</string>
+    <string name="remove_local_account">Remove local account</string>
+    <string name="remove_local_account_details">Remove account from device and delete all local files</string>
     <string name="remove_notification_failed">Failed to remove notification.</string>
     <string name="remove_push_notification">Remove</string>
     <string name="remove_success_msg">Deleted</string>
     <string name="rename_dialog_title">Enter a new name</string>
     <string name="rename_local_fail_msg">Could not rename local copy, try a different name</string>
     <string name="rename_server_fail_msg">Renaming not possible, name already taken</string>
+    <string name="request_account_deletion">Request account deletion</string>
+    <string name="request_account_deletion_button">Request deletion</string>
+    <string name="request_account_deletion_details">Request permanent deletion of account by service provider</string>
     <string name="reshare_not_allowed">Resharing is not allowed</string>
     <string name="resharing_is_not_allowed">Resharing is not allowed</string>
     <string name="resized_image_not_possible_download">No resized image available. Download full image?</string>
@@ -944,7 +952,9 @@
     <string name="wait_a_moment">Wait a moment…</string>
     <string name="wait_checking_credentials">Checking stored credentials</string>
     <string name="wait_for_tmp_copy_from_private_storage">Copying file from private storage</string>
+    <string name="webview_version_check_alert_dialog_message">Please update the Android System WebView app for a login</string>
     <string name="webview_version_check_alert_dialog_positive_button_title">Update</string>
+    <string name="webview_version_check_alert_dialog_title">Update Android System WebView</string>
     <string name="what_s_new_image">What\'s new image</string>
     <string name="whats_new_skip">Skip</string>
     <string name="whats_new_title">New in %1$s</string>

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

@@ -627,6 +627,7 @@
     <string name="rename_dialog_title">Въведете ново име</string>
     <string name="rename_local_fail_msg">Локалното копие не може да бъде преименувано; опитайте с друго име</string>
     <string name="rename_server_fail_msg">Сървърът не може да бъде преименуван</string>
+    <string name="request_account_deletion">Заявка за изтриване на профил</string>
     <string name="reshare_not_allowed">Повторното споделяне е забранено</string>
     <string name="resharing_is_not_allowed">Повторното споделяне е забранено</string>
     <string name="resized_image_not_possible_download">Няма налично оразмерено изображение. Да се свали ли изображението?</string>

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

@@ -518,6 +518,7 @@
     <string name="rename_dialog_title">Lakaat un anv nevez</string>
     <string name="rename_local_fail_msg">Dibosuple adenvel an eilenn diabarzh, klaskit un anv all</string>
     <string name="rename_server_fail_msg">Dibosuple adenvel, anv kemeret dija</string>
+    <string name="request_account_deletion">Goulenn lemel ar c\'hont</string>
     <string name="reshare_not_allowed">N\'eo ket aotreet an adrannan</string>
     <string name="resharing_is_not_allowed">N\'eo ket aotreet an adrannan</string>
     <string name="resized_image_not_possible_download">Skeudenn admentet ebet. Pellgargañ ar skeudenn glot ?</string>

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

@@ -618,6 +618,7 @@
     <string name="rename_dialog_title">Introduiu un nom nou</string>
     <string name="rename_local_fail_msg">No s\'ha pogut canviar el nom de la còpia local, intenteu-ho amb amb un altre nom</string>
     <string name="rename_server_fail_msg">El canvi de nom no és possible, el nom ja es troba en ús</string>
+    <string name="request_account_deletion">Sol·licitud de supressió de compte</string>
     <string name="reshare_not_allowed">No es pot tornar a compartir</string>
     <string name="resharing_is_not_allowed">No està permesa la re-compartició</string>
     <string name="resized_image_not_possible_download">No hi ha imatge redimensionada disponible. Voleu baixar la imatge a la resolució original?</string>

+ 8 - 0
app/src/main/res/values-cs-rCZ/strings.xml

@@ -160,6 +160,7 @@
     <string name="conflict_message_description">Pokud zvolíte obě verze, k názvu místního souboru bude připojeno číslo.</string>
     <string name="conflict_server_file">Soubor na serveru</string>
     <string name="contact_backup_title">Záloha kontaktů</string>
+    <string name="contact_no_permission">Je vyžadováno oprávnění pro přístup ke kontaktům.</string>
     <string name="contactlist_item_icon">Ikona uživatele v seznamu kontaktů</string>
     <string name="contactlist_no_permission">Nejsou udělena oprávnění, proto nebylo nic naimportováno.</string>
     <string name="contacts">Kontakty</string>
@@ -258,6 +259,7 @@
     <string name="ecosystem_apps_more">Další Nextcloud aplikace</string>
     <string name="ecosystem_apps_notes">Nextcloud poznámky</string>
     <string name="ecosystem_apps_talk">Nextcloud Talk</string>
+    <string name="email_pick_failed">Nepodařilo se vybrat e-mailovou adresu.</string>
     <string name="encrypted">Nastavit jako šifrované</string>
     <string name="end_to_end_encryption_confirm_button">Nastavit šifrování</string>
     <string name="end_to_end_encryption_decrypting">Rozšifrovávání…</string>
@@ -648,12 +650,17 @@
     <string name="remove_e2e">Je možné šifrování mezi koncovými body odebrat lokálně na tomto klientovi</string>
     <string name="remove_e2e_message">Je možné šifrování mezi koncovými body odebrat lokálně na tomto klientovi. Šifrované soubory zůstanou na serveru, ale už nadále nebudou synchronizovány s tímto počítačem.</string>
     <string name="remove_fail_msg">Odstranění se nezdařilo</string>
+    <string name="remove_local_account">Odebrat místní účet</string>
+    <string name="remove_local_account_details">Odebrat účet ze zařízení a smazat veškeré místní soubory</string>
     <string name="remove_notification_failed">Upozornění se nepodařilo odebrat.</string>
     <string name="remove_push_notification">Odebrat</string>
     <string name="remove_success_msg">Smazáno</string>
     <string name="rename_dialog_title">Zadejte nový název</string>
     <string name="rename_local_fail_msg">Nepodařilo se přejmenovat místní kopii – zkuste použít jiný název</string>
     <string name="rename_server_fail_msg">Přejmenování není možné – název už je použit</string>
+    <string name="request_account_deletion">Vyžádat smazání účtu</string>
+    <string name="request_account_deletion_button">Vyžádat si smazání</string>
+    <string name="request_account_deletion_details">Vyžádat si trvalé vymazání účtu u poskytovatele služby</string>
     <string name="reshare_not_allowed">Příjemcům tohoto sdílení není dovoleno ho nasdílet dál dalším</string>
     <string name="resharing_is_not_allowed">Příjemcům tohoto sdílení není dovoleno ho nasdílet dál dalším</string>
     <string name="resized_image_not_possible_download">Zmenšená verze obrázku není k dispozici. Stáhnout obrázek v plné velikosti?</string>
@@ -877,6 +884,7 @@
     <string name="upload_lock_failed">Uzamčení složky se nezdařilo</string>
     <string name="upload_old_android">Šifrování je možné pouze na systému Android verze 5.0 a novějším</string>
     <string name="upload_query_move_foreign_files">Pro zkopírování vybraných souborů do složky %1$s není dostatek volného místa. Chcete je tam namísto toho přesunout?</string>
+    <string name="upload_quota_exceeded">Kvóta úložiště překročena</string>
     <string name="upload_scan_doc_upload">Naskenovat dokument kamerou</string>
     <string name="upload_sync_conflict">Konflikt synchronizace – vyřešte ručně</string>
     <string name="upload_unknown_error">Neznámá chyba</string>

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

@@ -656,6 +656,7 @@ Enheds legitimationsoplysninger er sat op
     <string name="rename_dialog_title">Indtast et nyt navn</string>
     <string name="rename_local_fail_msg">Lokal kopi kunne ikke omdøbes, prøv et andet navn</string>
     <string name="rename_server_fail_msg">Omdøbning ikke mulig, navnet eksisterer</string>
+    <string name="request_account_deletion">Anmodning om sletning af konto</string>
     <string name="reshare_not_allowed">Gendeling er ikke tilladt</string>
     <string name="resharing_is_not_allowed">Videredeling ikke tilladt</string>
     <string name="resized_image_not_possible_download">Intet skaleret billede tilgængeligt. Hent fuldt billede?</string>

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

@@ -160,6 +160,7 @@
     <string name="conflict_message_description">Falls beide Versionen gewählt werden, wird bei der lokalen Datei eine Zahl am Ende des Dateinamens hinzugefügt.</string>
     <string name="conflict_server_file">Server-Datei</string>
     <string name="contact_backup_title">Kontakte-Backup</string>
+    <string name="contact_no_permission">Eine Kontakterlaubnis ist erforderlich.</string>
     <string name="contactlist_item_icon">Nutzericon für Kontaktliste</string>
     <string name="contactlist_no_permission">Keine Berechtigung vergeben, es wurde nichts importiert.</string>
     <string name="contacts">Kontakte</string>
@@ -258,6 +259,7 @@
     <string name="ecosystem_apps_more">Weitere Nextcloud-Apps</string>
     <string name="ecosystem_apps_notes">Nextcloud Notizen</string>
     <string name="ecosystem_apps_talk">Nextcloud Talk</string>
+    <string name="email_pick_failed">E-Mail-Adresse konnte nicht ausgewählt werden.</string>
     <string name="encrypted">Als verschlüsselt festlegen</string>
     <string name="end_to_end_encryption_confirm_button">Verschlüsselung einrichten</string>
     <string name="end_to_end_encryption_decrypting">Entschlüssele…</string>
@@ -648,12 +650,17 @@
     <string name="remove_e2e">Sie können die Ende-zu-Ende-Verschlüsselung lokal auf diesem Client entfernen</string>
     <string name="remove_e2e_message">Sie können die Ende-zu-Ende-Verschlüsselung lokal auf diesem Client entfernen. Die verschlüsselten Dateien bleiben auf dem Server, werden aber nicht mehr mit diesem Computer synchronisiert.</string>
     <string name="remove_fail_msg">Löschung fehlgeschlagen</string>
+    <string name="remove_local_account">Lokales Konto entfernen</string>
+    <string name="remove_local_account_details">Das Konto vom Gerät entfernen und alle lokalen Dateien löschen</string>
     <string name="remove_notification_failed">Entfernen der Benachrichtigungen fehlgeschlagen.</string>
     <string name="remove_push_notification">Entfernen</string>
     <string name="remove_success_msg">Gelöscht</string>
     <string name="rename_dialog_title">Geben Sie einen neuen Namen ein</string>
     <string name="rename_local_fail_msg">Die lokale Kopie konnte nicht umbenannt werden. Versuche es mit einem anderen Namen.</string>
     <string name="rename_server_fail_msg">Umbenennen nicht möglich. Der Name wird bereits verwendet.</string>
+    <string name="request_account_deletion">Kontolöschung anfordern</string>
+    <string name="request_account_deletion_button">Löschung anfordern</string>
+    <string name="request_account_deletion_details">Beim Diensteanbieter die dauerhafte Löschung des Kontos anfordern</string>
     <string name="reshare_not_allowed">Das Weiterverteilen ist nicht erlaubt </string>
     <string name="resharing_is_not_allowed">Resharing/Wiederteilen ist nicht erlaubt.</string>
     <string name="resized_image_not_possible_download">Kein verkleinertes Bild verfügbar. Vollbild herunterladen?</string>
@@ -878,6 +885,7 @@
     <string name="upload_lock_failed">Fehler beim Sperren des Ordners</string>
     <string name="upload_old_android">Verschlüsselung ist nur möglich mit &gt;= Android 5.0</string>
     <string name="upload_query_move_foreign_files">Es steht nicht genügend Speicherplatz zur Verfügung, um die ausgewählten Dateien in das Verzeichnis %1$s zu kopieren. Sollen diese stattdessen verschoben werden?</string>
+    <string name="upload_quota_exceeded">Speicherkontingent überschritten</string>
     <string name="upload_scan_doc_upload">Dokument von der Kamera scannen</string>
     <string name="upload_sync_conflict">Synchronisierungskonflikt, bitte manuell beheben</string>
     <string name="upload_unknown_error">Unbekannter Fehler</string>

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

@@ -633,6 +633,7 @@
     <string name="rename_dialog_title">Εισάγετε νέο όνομα</string>
     <string name="rename_local_fail_msg">Αδυναμία μετονομασίας τοπικού αντιγράφου, δοκιμάστε διαφορετικό όνομα</string>
     <string name="rename_server_fail_msg">Αδύνατη μετονομασία, το όνομα έχει ήδη δοθεί</string>
+    <string name="request_account_deletion">Αίτηση διαγραφής λογαριασμού</string>
     <string name="reshare_not_allowed">Δεν επιτρέπεται ο επαναμοιρασμός</string>
     <string name="resharing_is_not_allowed">Δεν επιτρέπεται ο διαμοιρασμός</string>
     <string name="resized_image_not_possible_download">Δεν υπάρχει διαθέσιμη εικόνα με αλλαγμένο μέγεθος. Κατέβασμα της πλήρους εικόνας;</string>

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

@@ -10,12 +10,14 @@
     <string name="action_clear_failed_uploads">Vakigi malsukcesajn alŝutojn</string>
     <string name="action_edit">Modifi</string>
     <string name="action_empty_notifications">Forviŝi ĉiujn sciigojn</string>
+    <string name="action_empty_trashbin">Malpleni rubujon</string>
     <string name="action_send_share">Sendi aŭ kunhavigi</string>
     <string name="action_switch_grid_view">Krada vido</string>
     <string name="action_switch_list_view">Lista vido</string>
     <string name="actionbar_copy">Kopii</string>
     <string name="actionbar_mkdir">Nova dosierujo</string>
     <string name="actionbar_move">Movi</string>
+    <string name="actionbar_move_or_copy">Movi aŭ Kopii</string>
     <string name="actionbar_open_with">Malfermi per</string>
     <string name="actionbar_search">Serĉi</string>
     <string name="actionbar_see_details">Detaloj</string>
@@ -77,6 +79,8 @@
     <string name="choose_local_folder">Elekti lokan dosierujon...</string>
     <string name="choose_remote_folder">Elekti foran dosierujon...</string>
     <string name="clear_notifications_failed">Malsukcesis forviŝi sciigojn.</string>
+    <string name="clear_status_message">Forviŝi statusan mesaĝon</string>
+    <string name="clear_status_message_after">Forviŝos statusan mesaĝon poste</string>
     <string name="clipboard_label">Teksto kopiita el %1$s</string>
     <string name="clipboard_no_text_to_copy">Neniu teksto ricevita por kopii tondujen</string>
     <string name="clipboard_text_copied">Ligilo kopiita</string>
@@ -103,6 +107,8 @@
     <string name="common_send">Sendi</string>
     <string name="common_share">Kunhavigi</string>
     <string name="common_skip">Preterpasi</string>
+    <string name="common_switch_account">Interŝanĝi konton</string>
+    <string name="common_switch_to_account">Ŝanĝi al konto</string>
     <string name="common_yes">Jes</string>
     <string name="community_beta_headline">Testu la beta-version</string>
     <string name="community_beta_text">Ĝi enhavas ĉiujn venontajn funkciojn, kaj ĝi estas freŝfreŝa. Eraroj povas okazi: se kaj kiam tio okazas, bonvolu raporti ilin.</string>
@@ -126,6 +132,8 @@
     <string name="confirmation_remove_folder_alert">Ĉu vi ja volas forigi %1$s kaj ĝian enhavon?</string>
     <string name="confirmation_remove_folders_alert">Ĉu vi ja volas forigi la elektitajn elementojn kaj ilian enhavon?</string>
     <string name="confirmation_remove_local">Nur loka</string>
+    <string name="conflict_local_file">Loka dosiero</string>
+    <string name="contact_backup_title">Savkopii kontaktojn</string>
     <string name="contactlist_item_icon">Uzanto-piktogramo por la kontaktlisto</string>
     <string name="contactlist_no_permission">Permeso ne donita, nenio importiĝis.</string>
     <string name="contacts">Kontaktoj</string>
@@ -143,6 +151,7 @@
     <string name="copy_to">Kopii al...</string>
     <string name="create">Krei</string>
     <string name="create_dir_fail_msg">Ne eblis krei dosierujon</string>
+    <string name="create_new">Krei nove</string>
     <string name="create_new_document">Krei novan dokumenton</string>
     <string name="create_new_folder">Krei novan dosierujon</string>
     <string name="create_new_presentation">Krei novan prezentaĵon</string>
@@ -448,6 +457,7 @@
     <string name="rename_dialog_title">Enigu novan nomon</string>
     <string name="rename_local_fail_msg">Ne eblis alinomi lokan kopion, provu uzi alian nomon</string>
     <string name="rename_server_fail_msg">Ne eblis alinomi: la nomo jam uziĝas</string>
+    <string name="request_account_deletion">Peti kontoforigadon</string>
     <string name="reshare_not_allowed">Rekunhavigo ne estas permesata</string>
     <string name="resharing_is_not_allowed">Re-kunhavigi ne estas permesita</string>
     <string name="resized_image_not_possible_download">Neniu regrandigita bildo disponeblas. Ĉu elŝuti originan bildon?</string>

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

@@ -635,6 +635,7 @@
     <string name="rename_dialog_title">Ingresa un nombre nuevo</string>
     <string name="rename_local_fail_msg">No se pudo renombrar la copia local, intenta con un nombre diferente </string>
     <string name="rename_server_fail_msg">No fue posible renombrar, el nombre ya está ocupado</string>
+    <string name="request_account_deletion">Solicitar eliminación de cuenta</string>
     <string name="reshare_not_allowed">No se permite volver a compartir</string>
     <string name="resharing_is_not_allowed">No está permitido recompartir</string>
     <string name="resized_image_not_possible_download">No hay una imagen a escala disponible. ¿Descargar la imagen completa? </string>

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

@@ -474,6 +474,7 @@
     <string name="rename_dialog_title">Ingresa un nombre nuevo</string>
     <string name="rename_local_fail_msg">No se pudo renombrar la copia local, intenta con un nombre diferente </string>
     <string name="rename_server_fail_msg">No fue posible renombrar, el nombre ya está ocupado</string>
+    <string name="request_account_deletion">Solicitar borrado de cuenta</string>
     <string name="reshare_not_allowed">No está permitido recompartir</string>
     <string name="resharing_is_not_allowed">No está permitido recompartir</string>
     <string name="resized_image_not_possible_download">No hay una imagen a escala disponible. ¿Descargar la imagen completa? </string>

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

@@ -160,6 +160,7 @@
     <string name="conflict_message_description">Si seleccionas ambas versiones, el archivo local tendrá un número añadido a su nombre.</string>
     <string name="conflict_server_file">Archivo del servidor</string>
     <string name="contact_backup_title">Respaldo de contactos</string>
+    <string name="contact_no_permission">Se requiere el permiso de contactos.</string>
     <string name="contactlist_item_icon">Icono de usuario para lista de contactos</string>
     <string name="contactlist_no_permission">No se han concedido permisos, por lo que no se ha importado nada</string>
     <string name="contacts">Contactos</string>
@@ -258,6 +259,7 @@
     <string name="ecosystem_apps_more">Más apps de Nextcloud</string>
     <string name="ecosystem_apps_notes">Nextcloud Notas</string>
     <string name="ecosystem_apps_talk">Nextcloud Talk</string>
+    <string name="email_pick_failed">Error al seleccionar dirección de correo.</string>
     <string name="encrypted">Establecer como cifrado</string>
     <string name="end_to_end_encryption_confirm_button">Configurar cifrado</string>
     <string name="end_to_end_encryption_decrypting">Descifrando…</string>
@@ -654,6 +656,7 @@
     <string name="rename_dialog_title">Introduce un nombre nuevo</string>
     <string name="rename_local_fail_msg">No se ha podido cambiar el nombre de la copia local, prueba un nombre diferente</string>
     <string name="rename_server_fail_msg">No se ha podido dar un nombre nuevo, el nombre ya está tomado</string>
+    <string name="request_account_deletion">Solicitar la eliminación de la cuenta</string>
     <string name="reshare_not_allowed">No se permite volver a compartir</string>
     <string name="resharing_is_not_allowed">No se permite compartir de nuevo</string>
     <string name="resized_image_not_possible_download">No se dispone de la imagen en otros tamaños. ¿Descargar en tamaño completo?</string>
@@ -945,7 +948,9 @@
     <string name="wait_a_moment">Espera un momento…</string>
     <string name="wait_checking_credentials">Comprobando las credenciales guardadas</string>
     <string name="wait_for_tmp_copy_from_private_storage">Copiando el archivo desde el almacenamiento privado.</string>
+    <string name="webview_version_check_alert_dialog_message">Por favor actualiza la aplicación WebView de Sistema Android para iniciar sesión</string>
     <string name="webview_version_check_alert_dialog_positive_button_title">Actualizar</string>
+    <string name="webview_version_check_alert_dialog_title">Actualiza WebView de Sistema Android</string>
     <string name="what_s_new_image">Imagen de Qué hay de nuevo</string>
     <string name="whats_new_skip">Omitir</string>
     <string name="whats_new_title">Nuevo en %1$s</string>

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

@@ -653,6 +653,7 @@
     <string name="rename_dialog_title">Idatzi izen berri bat</string>
     <string name="rename_local_fail_msg">Ezin izan da kopia lokala berrizendatu, saiatu beste izen batekin</string>
     <string name="rename_server_fail_msg">Ezin izan da berrizendatu, izena hartua zegoen</string>
+    <string name="request_account_deletion">Eskatu kontuaren ezabaketa</string>
     <string name="reshare_not_allowed">Birpartekatzea ez da onartzen</string>
     <string name="resharing_is_not_allowed">Birpartekatzea ez da onartzen</string>
     <string name="resized_image_not_possible_download">Ez dago tamainaz aldatutako irudirik eskuragarri. Irudi osoa deskargatu nahi duzu?</string>

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

@@ -653,6 +653,7 @@
     <string name="rename_dialog_title">نام جدید وارد کنید</string>
     <string name="rename_local_fail_msg">تغییر نام نسخه محلی امکان پذیر نیست ، نام دیگری را امتحان کنید</string>
     <string name="rename_server_fail_msg">تغییر نام ممکن نیست، این نام قبلا استفاده شده است</string>
+    <string name="request_account_deletion">درخواست حذف اکانت</string>
     <string name="reshare_not_allowed">اشتراک‌گذاری مجدد مجاز نمی باشد</string>
     <string name="resharing_is_not_allowed">اشتراک‌گذاری مجدد مجاز نمی باشد</string>
     <string name="resized_image_not_possible_download">هیچ تصویری تغییر اندازه شده‌ای در دسترس نیست. تصویر کامل را بارگیری می کنید؟</string>

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

@@ -622,6 +622,7 @@ GNU yleinen lisenssi, versio 2</string>
     <string name="rename_dialog_title">Anna uusi nimi</string>
     <string name="rename_local_fail_msg">Paikallisen kopion nimeä ei voitu muuttaa, yritä eri nimeä</string>
     <string name="rename_server_fail_msg">Nimen muutos epäonnistui, nimi on jo käytössä</string>
+    <string name="request_account_deletion">Pyydä tilin poistoa</string>
     <string name="reshare_not_allowed">Uudellenjako ei ole salluttu</string>
     <string name="resharing_is_not_allowed">Uudelleenjakaminen ei ole sallittu</string>
     <string name="resized_image_not_possible_download">Uuden kokoinen kuva ei ole saatavilla. Ladataanko täysikokoinen kuva?</string>

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

@@ -160,6 +160,7 @@
     <string name="conflict_message_description">Si vous sélectionnez les deux versions, le fichier local aura un numéro ajouté à son nom.</string>
     <string name="conflict_server_file">Fichier serveur</string>
     <string name="contact_backup_title">Sauvegarde des contacts</string>
+    <string name="contact_no_permission">La permission d\'accès à vos contacts est requise</string>
     <string name="contactlist_item_icon">L\'icône de l\'utilisateur pour la liste des contacts</string>
     <string name="contactlist_no_permission">Pas de permission donnée, rien n\'a été importé.</string>
     <string name="contacts">Contacts</string>
@@ -650,12 +651,15 @@ Attention, la suppression est irréversible.</string>
     <string name="remove_e2e">Vous pouvez retirer le chiffrement de bout en bout localement sur ce client</string>
     <string name="remove_e2e_message">Vous pouvez retirer le chiffrement de bout en bout localement sur ce client. Les fichiers chiffrés resteront sur le serveur, mais ne seront plus synchronisés avec cet ordinateur.</string>
     <string name="remove_fail_msg">Échec de la suppression</string>
+    <string name="remove_local_account">Supprimer le compte local</string>
+    <string name="remove_local_account_details">Supprimer le compte de l\'appareil et supprimer tous les fichiers locaux</string>
     <string name="remove_notification_failed">Erreur lors de la suppression des notifications.</string>
     <string name="remove_push_notification">Supprimer</string>
     <string name="remove_success_msg">Supprimé</string>
     <string name="rename_dialog_title">Entrez un nouveau nom</string>
     <string name="rename_local_fail_msg">Impossible de renommer la version locale; veuillez réessayer avec un nom différent</string>
     <string name="rename_server_fail_msg">Impossible de renommer, le nom est déjà utilisé</string>
+    <string name="request_account_deletion">Demander la suppression du compte</string>
     <string name="reshare_not_allowed">Le repartage n\'est pas autorisé</string>
     <string name="resharing_is_not_allowed">Le repartage est interdit</string>
     <string name="resized_image_not_possible_download">Aucune image réduite disponible. Télécharger l\'image originale ?</string>

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

@@ -160,6 +160,7 @@
     <string name="conflict_message_description">Se selecciona ambas versións, o ficheiro local terá un número engadido ao nome.</string>
     <string name="conflict_server_file">Ficheiro do servidor</string>
     <string name="contact_backup_title">Copia de seguranza dos contactos</string>
+    <string name="contact_no_permission">Precisase de permiso de contacto.</string>
     <string name="contactlist_item_icon">Icona do usuario para a lista de contactos</string>
     <string name="contactlist_no_permission">Non se concederon permisos. Non se importou nada!</string>
     <string name="contacts">Contactos</string>
@@ -258,6 +259,7 @@
     <string name="ecosystem_apps_more">Máis aplicacións de Nextcloud</string>
     <string name="ecosystem_apps_notes">Notas de Nextcloud</string>
     <string name="ecosystem_apps_talk">Talk de Nextcloud</string>
+    <string name="email_pick_failed">Produciuse un fallo ao escoller o enderezo de correo.</string>
     <string name="encrypted">Estabelecer como cifrado</string>
     <string name="end_to_end_encryption_confirm_button">Configurar o cifrado</string>
     <string name="end_to_end_encryption_decrypting">Descifrando…</string>
@@ -649,12 +651,17 @@
     <string name="remove_e2e">Pode retirar o cifrado de extremo a extremo localmente neste cliente</string>
     <string name="remove_e2e_message">Pode retirar o cifrado de extremo a extremo localmente neste cliente. Os ficheiros cifrados permanecerán no servidor, mais xa non se sincronizarán con este computador.</string>
     <string name="remove_fail_msg">Produciuse un fallo na eliminación</string>
+    <string name="remove_local_account">Retirar a conta local</string>
+    <string name="remove_local_account_details">Retirar a conta do dispositivo e eliminar todos os ficheiros locais</string>
     <string name="remove_notification_failed">Produciuse un fallo ao retirar a notificación.</string>
     <string name="remove_push_notification">Retirar</string>
     <string name="remove_success_msg">Eliminado</string>
     <string name="rename_dialog_title">Introduza un nome novo</string>
     <string name="rename_local_fail_msg">Non foi posíbel renomear a copia local, ténteo cun un nome diferente</string>
     <string name="rename_server_fail_msg">Non foi posíbel renomear, o nome xa está ocupado</string>
+    <string name="request_account_deletion">Solicitar a eliminación da conta </string>
+    <string name="request_account_deletion_button">Solicitat a eliminación</string>
+    <string name="request_account_deletion_details">Solicitar a eliminación definitiva da conta polo provedor de servizos</string>
     <string name="reshare_not_allowed">Non se permite volver compartir</string>
     <string name="resharing_is_not_allowed">Non se permite volver compartir</string>
     <string name="resized_image_not_possible_download">No se dispón da imaxe noutros tamaños. Descargala a tamaño real?</string>
@@ -878,6 +885,7 @@
     <string name="upload_lock_failed">Produciuse un fallo ao bloquear o cartafol</string>
     <string name="upload_old_android">O cifrado só é posíbel con &gt;= Android 5.0</string>
     <string name="upload_query_move_foreign_files">Non hai espazo abondo para copiar os ficheiros seleccionados no cartafol %1$s. No canto diso, gustaríalle movelos?</string>
+    <string name="upload_quota_exceeded">Superouse a cota de almacenamento</string>
     <string name="upload_scan_doc_upload">Escanear o documento dende a cámara</string>
     <string name="upload_sync_conflict">Conflito ao sincronizar, resólvao manualmente</string>
     <string name="upload_unknown_error">Produciuse un erro descoñecido</string>

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

@@ -596,6 +596,7 @@
     <string name="rename_dialog_title">Unesite novi naziv</string>
     <string name="rename_local_fail_msg">Nije moguće preimenovati lokalnu kopiju, pokušajte s drugim nazivom</string>
     <string name="rename_server_fail_msg">Preimenovanje nije moguće, naziv je već zauzet</string>
+    <string name="request_account_deletion">Zatraži brisanje računa</string>
     <string name="reshare_not_allowed">Ponovno dijeljenje nije dopušteno</string>
     <string name="resharing_is_not_allowed">Ponovno dijeljenje nije dopušteno</string>
     <string name="resized_image_not_possible_download">Nema dostupne slike promijenjene veličine. Preuzeti punu sliku?</string>
@@ -732,8 +733,8 @@
     <string name="stream_not_possible_message">Umjesto toga preuzmite medijske datoteke ili se koristite vanjskom aplikacijom.</string>
     <string name="strict_mode">Ograničeni način rada: nije dopuštena HTTP veza!</string>
     <string name="sub_folder_rule_year">Godina</string>
-    <string name="subject_shared_with_you">\\"%1$s\\" je dijeljen s vama</string>
-    <string name="subject_user_shared_with_you">%1$s dijeli \\"%2$s\\" s vama</string>
+    <string name="subject_shared_with_you">\"%1$s\" je dijeljen s vama</string>
+    <string name="subject_user_shared_with_you">%1$s dijeli \"%2$s\" s vama</string>
     <string name="subtitle_photos_only">Samo fotografije</string>
     <string name="subtitle_photos_videos">Fotografije &amp; video materijali</string>
     <string name="subtitle_videos_only">Samo video materijali</string>

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

@@ -654,6 +654,7 @@
     <string name="rename_dialog_title">Adjon meg egy új nevet</string>
     <string name="rename_local_fail_msg">A helyi másolat nem nevezhető át, próbáljon meg egy másik nevet</string>
     <string name="rename_server_fail_msg">Nem nevezhető át, ez a név már foglalt</string>
+    <string name="request_account_deletion">Fióktörlés kérése</string>
     <string name="reshare_not_allowed">Az újra megosztás nem engedélyezett</string>
     <string name="resharing_is_not_allowed">Az újra megosztás nem engedélyezett</string>
     <string name="resized_image_not_possible_download">Nincs elérhető átméretezett kép. Letölti a teljes képet?</string>

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

@@ -18,6 +18,7 @@
     <string name="actionbar_copy">Salin</string>
     <string name="actionbar_mkdir">Folder baru</string>
     <string name="actionbar_move">Pindah</string>
+    <string name="actionbar_move_or_copy">Pindah atau Salin</string>
     <string name="actionbar_open_with">Buka dengan</string>
     <string name="actionbar_search">Cari</string>
     <string name="actionbar_see_details">Rincian</string>
@@ -88,7 +89,7 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini
     <string name="calendars">Kalender</string>
     <string name="certificate_load_problem">Terjadi permasalahan memuat sertifikat.</string>
     <string name="changelog_dev_version">Perubahan versi dev</string>
-    <string name="checkbox">Kotak check</string>
+    <string name="checkbox">Kotak centang</string>
     <string name="choose_local_folder">Pilih folder lokal…</string>
     <string name="choose_location">Pilih lokasi</string>
     <string name="choose_remote_folder">Pilih folder remot…</string>
@@ -152,7 +153,11 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini
     <string name="conflict_dialog_error">Galat saat membuat dialog konflik!</string>
     <string name="conflict_file_headline">File konflik %1$s</string>
     <string name="conflict_local_file">File lokal</string>
+    <string name="conflict_message_description">Jika Anda memilih kedua versi, nama dari berkas lokal akan ditambahi angka.</string>
     <string name="conflict_server_file">File server</string>
+    <string name="contact_backup_title">Pencadangan kontak</string>
+    <string name="contact_no_permission">Izin kontak diperlukan.</string>
+    <string name="contactlist_item_icon">Ikon pengguna untuk daftar kontak</string>
     <string name="contactlist_no_permission">Tidak ada perizinan diberikan, tidak ada yang terimpor</string>
     <string name="contacts">Kontak</string>
     <string name="contacts_backup_button">Cadangkan sekarang.</string>
@@ -166,6 +171,7 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini
     <string name="copy_file_invalid_overwrite">Berkas sudah ada didalam folder tujuan</string>
     <string name="copy_file_not_found">Tidak dapat menyalin. Silakan periksa apakah berkas eksis.</string>
     <string name="copy_link">Salin tautan</string>
+    <string name="copy_move_to_encrypted_folder_not_supported">Menyalin/memindah ke folder terenkripsi saat ini tidak didukung.</string>
     <string name="copy_to">Salin ke…</string>
     <string name="could_not_download_image">Tidak bisa unduh gambar penuh</string>
     <string name="could_not_retrieve_url">Tidak dapat mengambil URL</string>
@@ -192,16 +198,24 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini
     <string name="dev_version_no_information_available">Informasi tidak tersedia</string>
     <string name="dev_version_no_new_version_available">Tidak ada versi baru tersedia</string>
     <string name="dialog_close">Tutup</string>
+    <string name="did_not_check_for_dupes">Tidak mengecek duplikat.</string>
     <string name="digest_algorithm_not_available">Algoritma ini tidak tersedia di ponsel Anda.</string>
     <string name="direct_login_failed">Login melalui tautan langsung gagal!</string>
+    <string name="direct_login_text">Masuk dengan %1$s ke %2$s</string>
     <string name="disable_new_media_folder_detection_notifications">Nonaktifkan</string>
     <string name="dismiss">Batal</string>
     <string name="dismiss_notification_description">Abaikan notifikasi</string>
+    <string name="displays_mnemonic">Menampilkan sandi 12 kata Anda</string>
     <string name="dnd">Jangan diganggu</string>
     <string name="document_scan_export_dialog_images">Banyak gambar</string>
+    <string name="document_scan_export_dialog_pdf">Berkas PDF</string>
+    <string name="document_scan_export_dialog_title">Pilih jenis ekspor</string>
+    <string name="document_scan_pdf_generation_failed">Gagal membuat PDF</string>
     <string name="document_scan_pdf_generation_in_progress">Membuat PDF…</string>
     <string name="done">Selesai</string>
     <string name="dontClear">Jangan dihapus</string>
+    <string name="download_cannot_create_file">Tidak dapat membuat berkas lokal</string>
+    <string name="download_download_invalid_local_file_name">Nama berkas tidak valid untuk berkas lokal</string>
     <string name="download_latest_dev_version">Unduh versi dev terbaru</string>
     <string name="downloader_download_failed_content">Tidak bisa mengunduh %1$s</string>
     <string name="downloader_download_failed_credentials_error">Unduhan gagal, coba masuk kembali</string>
@@ -214,10 +228,12 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini
     <string name="downloader_not_downloaded_yet">Belum diunduh</string>
     <string name="drawer_close">Tutup jendela samping</string>
     <string name="drawer_community">Komunitas</string>
+    <string name="drawer_header_background">Gambar latar belakang tajuk laci</string>
     <string name="drawer_item_activities">Aktivitas</string>
     <string name="drawer_item_all_files">Semua berkas</string>
     <string name="drawer_item_favorites">Disukai</string>
     <string name="drawer_item_gallery">Media</string>
+    <string name="drawer_item_groupfolders">Folder kelompok</string>
     <string name="drawer_item_home">Beranda</string>
     <string name="drawer_item_notifications">Pemberitahuan</string>
     <string name="drawer_item_on_device">Dalam perangkat</string>
@@ -230,8 +246,14 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini
     <string name="drawer_quota">%1$s dari %2$s sudah digunakan</string>
     <string name="drawer_quota_unlimited">%1$s digunakan</string>
     <string name="drawer_synced_folders">Unggah otomatis.</string>
+    <string name="e2e_not_yet_setup">E2E belum dipersiapkan</string>
+    <string name="e2e_offline">Tidak bisa dilakukan tanpa koneksi internet</string>
+    <string name="ecosystem_apps_display_more">Lainnya</string>
+    <string name="ecosystem_apps_display_notes">Catatan</string>
     <string name="ecosystem_apps_display_talk">Talk</string>
+    <string name="ecosystem_apps_more">Aplikasi Nextcloud Lainnya</string>
     <string name="ecosystem_apps_notes">Catatan Nextcloud</string>
+    <string name="email_pick_failed">Gagal memilih alamat surel.</string>
     <string name="encrypted">Atur sebagai terenkripsi</string>
     <string name="end_to_end_encryption_confirm_button">Buat enkripsi</string>
     <string name="end_to_end_encryption_decrypting">Mendekripsi...</string>
@@ -239,11 +261,14 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini
     <string name="end_to_end_encryption_enter_password">Silakan masukkan password untuk mendekripsi kunci pribadi</string>
     <string name="end_to_end_encryption_folder_not_empty">Folder ini tidak kosong.</string>
     <string name="end_to_end_encryption_generating_keys">Membuat kunci baru...</string>
+    <string name="end_to_end_encryption_keywords_description">Seluruh 12 kata menghasilkan sandi yang sangat kuat, memungkinkan Anda melihat dan mempergunakan berkas-berkas Anda yang terenkripsi. Harap tulis sandi tersebut dan simpan di tempat aman.</string>
     <string name="end_to_end_encryption_not_enabled">Enkripsi end-to-end dinonaktifkan di server</string>
+    <string name="end_to_end_encryption_passphrase_title">Catatlah sandi enkripsi 12 kata Anda</string>
     <string name="end_to_end_encryption_password">Kata Sandi…</string>
     <string name="end_to_end_encryption_retrieving_keys">Menerima kunci...</string>
     <string name="end_to_end_encryption_storing_keys">Menyimpan kunci</string>
     <string name="end_to_end_encryption_title">Buat enkripsi</string>
+    <string name="end_to_end_encryption_unsuccessful">Tidak dapat menyimpan kunci, harap coba lagi.</string>
     <string name="end_to_end_encryption_wrong_password">Error saat mendekripsi. Kata sandi salah?</string>
     <string name="enter_destination_filename">Masukkan nama file tujuan</string>
     <string name="enter_filename">Tolong masukan nama berkas baru</string>
@@ -251,10 +276,12 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini
     <string name="error_cant_bind_to_operations_service">Kesalahan fatal: tidak dapat melakukan operasi</string>
     <string name="error_choosing_date">Terjadi kesalahan dalam memilih tanggal</string>
     <string name="error_comment_file">Error saat mengomentari file</string>
+    <string name="error_creating_file_from_template">Galat saat membuat berkas dari templat</string>
     <string name="error_file_lock">Error saat mengubah status kunci file</string>
     <string name="error_report_issue_action">Laporan</string>
     <string name="error_retrieving_file">Galat saat menerima file</string>
     <string name="error_retrieving_templates">Error saat mengambil template</string>
+    <string name="error_showing_encryption_dialog">Galat saat menampilkan dialog penyiapan enkripsi!</string>
     <string name="error_starting_direct_camera_upload">Galat saat mengaktifkan kamera</string>
     <string name="error_starting_doc_scan">Galat memulai pemindaian dokumen</string>
     <string name="etm_accounts">Akun</string>
@@ -266,34 +293,44 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini
     <string name="etm_background_job_uuid">UUID</string>
     <string name="etm_background_jobs">Pekerjaan latar belakang</string>
     <string name="etm_background_jobs_cancel_all">Batalkan semua pekerjaan</string>
+    <string name="etm_background_jobs_prune">Pangkas pekerjaan yang tidak aktif</string>
     <string name="etm_preferences">Preferensi</string>
     <string name="etm_transfer_type">Transfer</string>
     <string name="etm_transfer_type_download">Unduh</string>
     <string name="etm_transfer_type_upload">Unggah</string>
     <string name="fab_label">Tambahkan atau unggah</string>
+    <string name="failed_to_download">Gagal memberikan berkas ke pengelola unduhan</string>
+    <string name="failed_to_print">Gagal mencetak berkas</string>
+    <string name="failed_to_start_editor">Gagal memulai editor</string>
     <string name="failed_update_ui">Gagal memperbarui UI</string>
     <string name="favorite">Tambah ke favorit</string>
     <string name="favorite_icon">Favorit</string>
     <string name="file_already_exists">Berkas sudah ada</string>
     <string name="file_delete">Hapus</string>
+    <string name="file_detail_activity_error">Gagal mendapatkan aktivitas untuk berkas</string>
     <string name="file_details_no_content">Gagal memuat detil</string>
     <string name="file_icon">Berkas</string>
     <string name="file_keep">Simpan</string>
     <string name="file_list_empty">Unggah beberapa berkas atau sinkronisasi dengan perangkat anda.</string>
     <string name="file_list_empty_favorite_headline">Belum ada yang disukai.</string>
     <string name="file_list_empty_favorites_filter_list">Berkas dan folder yang Anda tandai sebagai favorit akan ditampilkan di sini.</string>
+    <string name="file_list_empty_gallery">Tidak menemukan gambar atau video</string>
     <string name="file_list_empty_headline">Tidak ada berkas</string>
     <string name="file_list_empty_headline_search">Tidak ada hasil di folder ini</string>
     <string name="file_list_empty_headline_server_search">Tidak ada hasil.</string>
     <string name="file_list_empty_moving">Kosong. Anda dapat menambahkan folder</string>
+    <string name="file_list_empty_on_device">Berkas dan folder yang diunduh akan muncul di sini.</string>
     <string name="file_list_empty_recently_modified">Tidak ditemukan berkas yang diubah 7 hari terakhir</string>
     <string name="file_list_empty_search">Mungkin ada di folder yang berbeda?</string>
+    <string name="file_list_empty_shared">Berkas dan folder yang Anda bagikan akan muncul di sini.</string>
     <string name="file_list_empty_shared_headline">Belum ada yang dibagikan.</string>
+    <string name="file_list_empty_unified_search_no_results">Tidak ada hasil yang ditemukan untuk kueri Anda</string>
     <string name="file_list_folder">folder</string>
     <string name="file_list_loading">Memuat…</string>
     <string name="file_list_no_app_for_file_type">Tidak ada aplikasi untuk membuka jenis berkas ini.</string>
     <string name="file_list_seconds_ago">beberapa detik yang lalu</string>
     <string name="file_management_permission">Hak akses diperlukan</string>
+    <string name="file_management_permission_optional">Izin penyimpanan</string>
     <string name="file_migration_checking_destination">Memeriksa tujuan…</string>
     <string name="file_migration_cleaning">Membersihkan…</string>
     <string name="file_migration_failed_dir_already_exists">Direktori NextCloud sudah ada</string>
@@ -600,6 +637,7 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini
     <string name="unset_favorite">Hapus dari favorit</string>
     <string name="unshare_link_forbidden_permissions">untuk batal membagikan berkas ini</string>
     <string name="update_link_forbidden_permissions">untuk memperbarui pembagian ini</string>
+    <string name="upload_cannot_create_file">Tidak dapat membuat berkas lokal</string>
     <string name="upload_chooser_title">Unggah dari…</string>
     <string name="upload_content_from_other_apps">Unggah konten dari aplikasi lain</string>
     <string name="upload_direct_camera_upload">Unggah dari kamera</string>

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

@@ -373,6 +373,7 @@
     <string name="link">Tengill</string>
     <string name="link_share_allow_upload_and_editing">Leyfa innsendingu og breytingar</string>
     <string name="link_share_file_drop">Slepping skráa (einungis innsending)</string>
+    <string name="link_share_view_only">Einungis skoða</string>
     <string name="list_layout">Framsetning sem listi</string>
     <string name="load_more_results">Hlaða inn fleiri niðurstöðum</string>
     <string name="local_file_list_empty">Það eru engar skrár í þessari möppu.</string>
@@ -540,6 +541,7 @@
     <string name="rename_dialog_title">Settu inn nýtt nafn</string>
     <string name="rename_local_fail_msg">Gat endurnefnt staðvært afrit, prófaðu annað heiti</string>
     <string name="rename_server_fail_msg">Ekki hægt að endurnefna, heitið er frátekið</string>
+    <string name="request_account_deletion">Biðja um að aðgangi sé eytt</string>
     <string name="reshare_not_allowed">Endurdeiling er ekki leyfð</string>
     <string name="resharing_is_not_allowed">Endurdeiling er ekki leyfð</string>
     <string name="resized_image_not_possible_download">Engin stærðarbreytt mynd í boði. Sækja alla myndina?</string>
@@ -588,6 +590,8 @@
     <string name="share_no_password_title">Skrá lykilorð</string>
     <string name="share_password_title">Verja með lykilorði</string>
     <string name="share_permission_can_edit">Getur breytt</string>
+    <string name="share_permission_file_drop">Slepping skráa</string>
+    <string name="share_permission_view_only">Einungis skoða</string>
     <string name="share_remote_clarification">%1$s (fjartengt)</string>
     <string name="share_room_clarification">%1$s (samtal)</string>
     <string name="share_send_note">Minnispunktur til viðtakanda</string>

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

@@ -18,6 +18,7 @@
     <string name="actionbar_copy">Copia</string>
     <string name="actionbar_mkdir">Nuova cartella</string>
     <string name="actionbar_move">Sposta</string>
+    <string name="actionbar_move_or_copy">Sposta o copia</string>
     <string name="actionbar_open_with">Apri con</string>
     <string name="actionbar_search">Cerca</string>
     <string name="actionbar_see_details">Dettagli</string>
@@ -159,6 +160,7 @@
     <string name="conflict_message_description">Se selezioni entrambe le versioni, il file locale ha un numero aggiunto al suo nome.</string>
     <string name="conflict_server_file">File su server</string>
     <string name="contact_backup_title">Backup contatti</string>
+    <string name="contact_no_permission">Autorizzazione Contatti richiesta</string>
     <string name="contactlist_item_icon">Icona utente della lista contatti</string>
     <string name="contactlist_no_permission">Nessun permesso specificato, nessun elemento importato.</string>
     <string name="contacts">Contatti</string>
@@ -257,6 +259,7 @@
     <string name="ecosystem_apps_more">Altre app di Nextcloud</string>
     <string name="ecosystem_apps_notes">Nextcloud Notes</string>
     <string name="ecosystem_apps_talk">Nextcloud Talk</string>
+    <string name="email_pick_failed">Impossibile scegliere l\'indirizzo di posta.</string>
     <string name="encrypted">Imposta come cifrato</string>
     <string name="end_to_end_encryption_confirm_button">Configura la cifratura</string>
     <string name="end_to_end_encryption_decrypting">Decifratura in corso…</string>
@@ -647,12 +650,17 @@
     <string name="remove_e2e">Su questo client puoi rimuovere localmente la cifratura end-to-end</string>
     <string name="remove_e2e_message">Su questo client puoi rimuovere localmente la cifratura end-to-end. I file cifrati rimarranno sul server, ma non verranno più sincronizzati su questo computer.</string>
     <string name="remove_fail_msg">Eliminazione non riuscita</string>
+    <string name="remove_local_account">Rimuovi account locale</string>
+    <string name="remove_local_account_details">Rimuovi account dal dispositivo e elimina tutti i file locali</string>
     <string name="remove_notification_failed">Rimozione notifica non riuscita.</string>
     <string name="remove_push_notification">Rimuovi</string>
     <string name="remove_success_msg">Eliminato</string>
     <string name="rename_dialog_title">Digita un nuovo nome</string>
     <string name="rename_local_fail_msg">La copia locale non può essere rinominata, prova un nome diverso</string>
     <string name="rename_server_fail_msg">Rinomina non consentita, nome già utilizzato</string>
+    <string name="request_account_deletion">Richiesta di eliminazione account</string>
+    <string name="request_account_deletion_button">Richiedi eliminazione</string>
+    <string name="request_account_deletion_details">Richiedi l\'eliminazione permanente dell\'account al fornitore del servizio</string>
     <string name="reshare_not_allowed">La ri-condivisione non è consentita</string>
     <string name="resharing_is_not_allowed">La ri-condivisione non è consentita</string>
     <string name="resized_image_not_possible_download">Immagine ridimensionata non disponibile. Scaricare l\'immagine completa?</string>
@@ -944,7 +952,9 @@
     <string name="wait_a_moment">Attendi…</string>
     <string name="wait_checking_credentials">Controllo delle credenziali memorizzate</string>
     <string name="wait_for_tmp_copy_from_private_storage">Copia file dall\'archiviazione privata</string>
+    <string name="webview_version_check_alert_dialog_message">Aggiorna l\'app System WebView di Android per accedere</string>
     <string name="webview_version_check_alert_dialog_positive_button_title">Aggiorna</string>
+    <string name="webview_version_check_alert_dialog_title">Aggiorna System WebView di Android</string>
     <string name="what_s_new_image">Immagine Cosa c\'è di nuovo</string>
     <string name="whats_new_skip">Salta</string>
     <string name="whats_new_title">Prima volta su %1$s</string>

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

@@ -540,6 +540,7 @@
     <string name="rename_dialog_title">נא להזין שם חדש</string>
     <string name="rename_local_fail_msg">לא ניתן לשנות שם של עותק מקומי, נא לנסות שם אחר</string>
     <string name="rename_server_fail_msg">אי אפשר לשנות שם, השם כבר תפוס</string>
+    <string name="request_account_deletion">בקשת מחיקת חשבון</string>
     <string name="reshare_not_allowed">שיתוף מחדש אסור</string>
     <string name="resharing_is_not_allowed">אסור לשתף מחדש</string>
     <string name="resized_image_not_possible_download">אין תמונה מוקטנת. להוריד את התמונה המלאה?</string>

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

@@ -641,6 +641,7 @@
     <string name="rename_dialog_title">新しい名前を入力</string>
     <string name="rename_local_fail_msg">ローカルコピーの名前が変更できません。別の名前を試してください</string>
     <string name="rename_server_fail_msg">名前の変更ができません。その名前は使われています</string>
+    <string name="request_account_deletion">アカウントの削除をリクエストする</string>
     <string name="reshare_not_allowed">再共有は許可されていません</string>
     <string name="resharing_is_not_allowed">再共有は許可されていません</string>
     <string name="resized_image_not_possible_download">サイズ変更された画像はありません。 フルイメージをダウンロードしますか?</string>

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

@@ -634,6 +634,7 @@
     <string name="rename_dialog_title">새 이름 입력</string>
     <string name="rename_local_fail_msg">로컬 파일의 이름을 변경할 수 없습니다. 다른 이름을 입력하십시오</string>
     <string name="rename_server_fail_msg">이름을 변경할 수 없음. 이름이 이미 사용중입니다.</string>
+    <string name="request_account_deletion">계정 삭제 요청</string>
     <string name="reshare_not_allowed">다시 공유할 수 없음</string>
     <string name="resharing_is_not_allowed">다시 공유할 수 없습니다</string>
     <string name="resized_image_not_possible_download">크기 조정된 사진을 사용할 수 없습니다. 원본 크기로 다운로드하시겠습니까?</string>

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

@@ -581,6 +581,7 @@
     <string name="rename_dialog_title">Įveskite naują pavadinimą</string>
     <string name="rename_local_fail_msg">Nepavyko pervadinti vietinės kopijos, pabandykite kitą pavadinimą</string>
     <string name="rename_server_fail_msg">Pervadinimas neįmanomas, pavadinimas jau užimtas</string>
+    <string name="request_account_deletion">Užklausti paskyros ištrynimo</string>
     <string name="reshare_not_allowed">Bendrinimas iš naujo yra neleidžiamas</string>
     <string name="resharing_is_not_allowed">Bendrinimas iš naujo yra neleidžiamas</string>
     <string name="resized_image_not_possible_download">Nėra prieinamas pakeisto dydžio paveikslas. Atsisiųsti pilno dydžio paveikslą?</string>

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

@@ -381,6 +381,7 @@
     <string name="rename_dialog_title">Ievadīt jaunu nosaukumu</string>
     <string name="rename_local_fail_msg">Nevarēja pārsaukt lokālo kopiju, pamēģiniet citu nosaukumu</string>
     <string name="rename_server_fail_msg">Pārsaukšana nav iespējama, nosaukums jau izmantots</string>
+    <string name="request_account_deletion">Pieprasīt konta dzēšanu</string>
     <string name="reshare_not_allowed">Atkārtota koplietošana nav atļauta</string>
     <string name="resharing_is_not_allowed">Atkārtota koplietošana nav atļauta</string>
     <string name="restore">Atjaunot datni</string>

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

@@ -550,6 +550,7 @@
     <string name="rename_dialog_title">Внеси ново име</string>
     <string name="rename_local_fail_msg">Локалната копија не може да се преименува; пробајте со друго име</string>
     <string name="rename_server_fail_msg">Преименувањето не е возможно, тоа име веќе е зафатено</string>
+    <string name="request_account_deletion">Барање за бришење на сметката</string>
     <string name="reshare_not_allowed">Повторно споделување не е дозволено</string>
     <string name="resharing_is_not_allowed">Повторно споделување не е дозволено</string>
     <string name="resized_image_not_possible_download">Нема достапно смалена слика. Превземете ја во целосната големина?</string>

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

@@ -654,6 +654,7 @@
     <string name="rename_dialog_title">Skriv inn et nytt navn</string>
     <string name="rename_local_fail_msg">Kunne ikke endre navn på lokal kopi, prøv et annet navn</string>
     <string name="rename_server_fail_msg">Endring av navn ikke mulig, navnet er allerde benyttet</string>
+    <string name="request_account_deletion">Request account deletion</string>
     <string name="reshare_not_allowed">Videre deling er ikke tillatt</string>
     <string name="resharing_is_not_allowed">Videredeling er ikke tillatt</string>
     <string name="resized_image_not_possible_download">Inget mindre bilde tilgjengelig. Last ned fullversjon?</string>

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

@@ -607,6 +607,7 @@
     <string name="rename_dialog_title">Voer een nieuwe naam in</string>
     <string name="rename_local_fail_msg">Kon lokale kopie niet hernoemen, probeer een andere naam</string>
     <string name="rename_server_fail_msg">Hernoemen niet mogelijk, naam is al in gebruik</string>
+    <string name="request_account_deletion">Verwijdering van account aanvragen </string>
     <string name="reshare_not_allowed">Verder delen niet toegestaan</string>
     <string name="resharing_is_not_allowed">Verder delen is niet toegestaan</string>
     <string name="resized_image_not_possible_download">Geen verkleinde afbeelding beschikbaar. Volledige afbeelding downloaden?</string>

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

@@ -160,6 +160,7 @@
     <string name="conflict_message_description">Jeśli wybierzesz obie wersje, to do nazwy pliku lokalnego zostanie dodany numer.</string>
     <string name="conflict_server_file">Plik z serwera</string>
     <string name="contact_backup_title">Kopia zapasowa kontaktów</string>
+    <string name="contact_no_permission">Wymagane jest pozwolenie na lokalizację</string>
     <string name="contactlist_item_icon">Ikona użytkownika w liście kontaktów</string>
     <string name="contactlist_no_permission">Brak nadanych uprawnień, nic nie zaimportowano.</string>
     <string name="contacts">Kontakty</string>
@@ -258,6 +259,7 @@
     <string name="ecosystem_apps_more">Więcej aplikacji Nextcloud</string>
     <string name="ecosystem_apps_notes">Nextcloud Notes</string>
     <string name="ecosystem_apps_talk">Nextcloud Talk</string>
+    <string name="email_pick_failed">Nie udało się wybrać adresu e-mail.</string>
     <string name="encrypted">Ustaw jako zaszyfrowane</string>
     <string name="end_to_end_encryption_confirm_button">Włącz szyfrowanie</string>
     <string name="end_to_end_encryption_decrypting">Odszyfrowywanie…</string>
@@ -654,6 +656,7 @@
     <string name="rename_dialog_title">Wprowadź nową nazwę</string>
     <string name="rename_local_fail_msg">Nie można zmienić nazwy lokalnej kopii, użyj innej nazwy</string>
     <string name="rename_server_fail_msg">Nie można zmienić nazwy, nazwa jest już zajęta</string>
+    <string name="request_account_deletion">Zażądaj usunięcia konta</string>
     <string name="reshare_not_allowed">Udostępnianie dalej jest niedozwolone</string>
     <string name="resharing_is_not_allowed">Udostępnianie dalej jest niedozwolone</string>
     <string name="resized_image_not_possible_download">Brak obrazu o zmienionym rozmiarze. Pobrać pełny obraz?</string>

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

@@ -653,6 +653,7 @@
     <string name="rename_dialog_title">Digite um novo nome</string>
     <string name="rename_local_fail_msg">Não foi possível renomear a cópia local, tente um nome diferente</string>
     <string name="rename_server_fail_msg">Não foi possível renomear pois o nome já existe</string>
+    <string name="request_account_deletion">Solicitar a exclusão da conta</string>
     <string name="reshare_not_allowed">Recompartilhamento não é permitido</string>
     <string name="resharing_is_not_allowed">Recompartilhamento não é permitido</string>
     <string name="resized_image_not_possible_download">Não há imagem redimensionada disponível. Baixar a imagem completa?</string>

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

@@ -636,6 +636,7 @@
     <string name="rename_dialog_title">Introduza um novo nome</string>
     <string name="rename_local_fail_msg">Não foi possível renomear a cópia local, tente um nome diferente</string>
     <string name="rename_server_fail_msg">Renomeação impossível, nome já utilizado</string>
+    <string name="request_account_deletion">Solicitar eliminação da conta</string>
     <string name="reshare_not_allowed">Voltar a partilhar não é permitido</string>
     <string name="resharing_is_not_allowed">Não é permitido voltar a partilhar</string>
     <string name="resized_image_not_possible_download">Nenhuma imagem redimensionada disponível. Deseja transferir a imagem completa?</string>

+ 9 - 6
app/src/main/res/values-ro/strings.xml

@@ -157,7 +157,7 @@
     <string name="conflict_local_file">Fișier local</string>
     <string name="conflict_message_description">Dacă selectezi ambele variante, atunci fișierul local va avea un număr adăugat la numele său.</string>
     <string name="conflict_server_file">Fișier pe server</string>
-    <string name="contact_backup_title">Backup (copie de rezervă) contacte</string>
+    <string name="contact_backup_title">Copie de rezervă contacte</string>
     <string name="contactlist_item_icon">Iconiță utilizator pentru lista de contacte</string>
     <string name="contactlist_no_permission">Nu sunt acordate permisiuni, nu s-a importat nimic.</string>
     <string name="contacts">Contacte</string>
@@ -203,6 +203,7 @@
     <string name="did_not_check_for_dupes">Nu s-au verificat duplicatele.</string>
     <string name="digest_algorithm_not_available">Algoritmul \'digest\' nu este disponibil pe telefonul tău.</string>
     <string name="direct_login_failed">Eroare la autentificare prin legătură directă!</string>
+    <string name="direct_login_text">Autentificare cu %1$s la %2$s</string>
     <string name="disable_new_media_folder_detection_notifications">Dezactivează</string>
     <string name="dismiss">Elimină</string>
     <string name="dismiss_notification_description">Elimină notificarea</string>
@@ -440,6 +441,7 @@
     <string name="locked_by_app">Blocat de aplicația%1$s </string>
     <string name="log_send_mail_subject">%1$s înregistrările app-ului Android</string>
     <string name="log_send_no_mail_app">Nu există nici o aplicație pentru a trimite fisiere log. Vă rugăm instalați un client de email.</string>
+    <string name="logged_in_as">Autentificat ca %1$s</string>
     <string name="login">Autentificare</string>
     <string name="login_url_helper_text">Linkul către %1$s interfața web atunci când deschizi linkul în browser.</string>
     <string name="logs_menu_delete">Șterge fișiere log</string>
@@ -569,7 +571,7 @@
     <string name="prefs_daily_contact_backup_summary">Salvarea zilnică a contactelor dvs.</string>
     <string name="prefs_e2e_active">Encripția end-to-end este setata!</string>
     <string name="prefs_e2e_mnemonic">E2E mnemonic</string>
-    <string name="prefs_e2e_no_device_credentials">Pentru a arăta fraza de memorare (mnemonic) vă rugăm activați acreditările dispozitivului.</string>
+    <string name="prefs_e2e_no_device_credentials">Pentru a arăta mnemonica activați credențialele pentru dispozitiv.</string>
     <string name="prefs_enable_media_scan_notifications">Afișează notificări despre scanarea media</string>
     <string name="prefs_enable_media_scan_notifications_summary">Notifică despre dosare media noi găsite</string>
     <string name="prefs_gpl_v2">Licența Publică Generală GNU, versiunea 2</string>
@@ -626,6 +628,7 @@
     <string name="rename_dialog_title">Introduceţi un nou nume</string>
     <string name="rename_local_fail_msg">Nu s-a putut redenumi copia locală, încercați un alt nume</string>
     <string name="rename_server_fail_msg">Redenumirea nu este posibilă, numele este deja luat</string>
+    <string name="request_account_deletion">Cerere ștergere cont</string>
     <string name="reshare_not_allowed">Repartajarea nu este permisă</string>
     <string name="resharing_is_not_allowed">Repartajarea nu este permisă</string>
     <string name="resized_image_not_possible_download">Nu există o imagine mai mică. Descărcați imaginea completă?</string>
@@ -754,8 +757,8 @@
     <string name="storage_permission_full_access">Acces complet</string>
     <string name="storage_permission_media_read_only">Media read-only</string>
     <string name="storage_pictures">Poze</string>
-    <string name="store_full_desc">Platforma de productivitate ce îți oferă ție ontrolul și poate fi găzduită de tine.\n\Caracteristici:\n* Interfață facilă, modernă, complet personalizată in aliniere cu tema serverului tău\n* Încarcă fișiere pe serverul tău Nextcloud\n* Partajează fișierele tale cu alții\n* Păstrează-ți fișierele și folderele preferate sincronizate\n* Căutare în toate folderele de pe serverul tău\n* Încărcare automată a fotografiilor și videoclipurilor făcute cu dispozitivul tău\n* Fii la curent cu toate notificările\n* Suport pentru conturi multiple\n* Acces securizat la datele tale prin amprentă sau PIN\n* Integrare cu DAVx5 (în trecut cunoscut ca DAVdroid) pentru configurarea ușoară a sincronizarii Calendarelor si Contactelor. \nTe rugăm să anunți orice fel de probleme la https://github.com/nextcloud/android/issues și discuți despre această aplicație la https://help.nextcloud.com/c/clients/android\n\nEști nou la Nextcloud? Nextcloud este un server privat pentru comunicare, sincronizare &amp; și partajare de fișiere. Este în întregime open-source și îl poți găzdui tu, sau poți plăti o companie să facă asta pentru tine. În acest fel, ești pe deplin în control asupra fotografiilor tale, a calendarului și informațiilor de contact, a documentelor și a orice altceva.\n\nAflă mai multe despre Nextcloud la https://nextcloud.com</string>
-    <string name="store_full_dev_desc">Poți găzdui propriile tale instrumente de productivitate, tu avînd controlul total.\nAceasta este versiunea oficială ce prezintă o mostră zilnică de funcționalități netestate, ce ar putea cauza instabilități șî pierdere de date. Aplicația este pentru utilizatori ce sunt dispuși să testeze și să raporteze eventualele erori sau probleme de funcționare. Nu folosiți această aplicație pentru muncă productivă!\n]nAmbele versiuni pentru dezvoltatori și versiunea normală sunt disponibile pe F-Droid, și pot fii instalate în același timp.</string>
+    <string name="store_full_desc">Platfoma locală de productivitate care vă menține în control.\n\nCaracteristici:\n* Interfață simplă, modernă, adaptată temei serverului\n* Încărcați fișiere în serverul Nextcloud\n* Partajați-le cu alții\n* Țineți fișierele și folderele preferate sincronizate\n* Căutați prin toate folderele de pe server\n* Auto Încărcarea fotografiilor și clipurilor video făcute de dispozitivul personal\n* Fiți la curent cu notificările\n* Suport pentru Multi-account\n* Acces sigur la date cu amprentă sau PIN\n* Integrae cu DAVx5 (anterior DAVdroid) pentru setarea simplă a sincronizării calendarului &amp; Contactelor\n\nRaportați orice problemă la https://github.com/nextcloud/android/issues și discutați despre această aplicație la https://help.nextcloud.com/c/clients/android\n\nNew cu Nextcloud? Nextcloud este un server privat de sincronizare fișiere &amp; partajare și de comunicație. Este un software gratuit și puteți să-l găzduiți sau să plătiți o companie să o facă pentru dumneavoastră. Aveți astfel control asupra fotografiilor, datelor calendarului și despre contacte, documentelor și orice altceva.\n\nVizitați Nextcloud la https://nextcloud.com</string>
+    <string name="store_full_dev_desc">Platforma de productivitate locală care vă menține în control.\nAceasta este versiunea de dezvoltare oficială, cuprinzând exemple zilnice de funcționalități netestate, care pot crea instabilitate sau pierderi de date. Aplicația este pentru utilizatori care doresc să testeze și să raporteze bug-uri dacă acestea apar. Nu folosiți în producție!\n\n Și versiunea oficială de dezvoltare și cea stabilă sunt disponibile pe F-droid și pot fi instalate în același timp.</string>
     <string name="store_short_desc">Platforma găzduită și controlată de tine</string>
     <string name="store_short_dev_desc">Platforma găzduită și controlată de tine(versiunea pentru dezvoltatori)</string>
     <string name="stream">Transmite cu...</string>
@@ -815,7 +818,7 @@
     <string name="unread_comments">Există comentarii necitite</string>
     <string name="unset_encrypted">Dezactivați criptarea</string>
     <string name="unset_favorite">Ștergeți din favorite</string>
-    <string name="unshare_link_file_error">A apărut o eroare în timp ce încerca să se elimine partajarea (unshare) pentru acest fișier sau folder.</string>
+    <string name="unshare_link_file_error">A apărut o eroare la eliminarea partajării acestui fișier sau folder.</string>
     <string name="unshare_link_file_no_exist">Imposibil de șters partajarea. Te rugăm să verifici dacă există fișierul.</string>
     <string name="unshare_link_forbidden_permissions">de a nu permite accesul la acest fisier</string>
     <string name="unsharing_failed">Ștergerea partajării a eșuat</string>
@@ -843,7 +846,6 @@
     <string name="upload_local_storage_full">Stocarea locală este plină</string>
     <string name="upload_local_storage_not_copied">Fișierul nu a putut fi copiat în memoria locală</string>
     <string name="upload_lock_failed">Blocarea dosarului a eșuat</string>
-    <string name="upload_old_android">Criptarea este posibilă numai cu > = Android 5.0</string>
     <string name="upload_query_move_foreign_files">Nu există spațiu suficient pentru a copia fișierele selectate în dosarul %1$s. Doriți să le mutați în schimb?</string>
     <string name="upload_scan_doc_upload">Scanați documentul cu camera foto</string>
     <string name="upload_sync_conflict">Conflict de sincronizare, vă rugăm rezolvați  problema manual</string>
@@ -913,6 +915,7 @@
     <string name="wait_a_moment">Așteaptă un moment…</string>
     <string name="wait_checking_credentials">Se verifică datele de autentificare stocate</string>
     <string name="wait_for_tmp_copy_from_private_storage">Copiere fișier din stocare privată</string>
+    <string name="webview_version_check_alert_dialog_message">Pentru a vă autentifica, actualizați componenta WebView a sistemului Android</string>
     <string name="webview_version_check_alert_dialog_positive_button_title">Actualizare</string>
     <string name="what_s_new_image">Ce imagine este nouă</string>
     <string name="whats_new_skip">Sari peste</string>

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

@@ -655,6 +655,7 @@
     <string name="rename_dialog_title">Введите новое имя</string>
     <string name="rename_local_fail_msg">Невозможно переименовать локальную копию, попробуйте другое имя</string>
     <string name="rename_server_fail_msg">Переименование невозможно, имя занято</string>
+    <string name="request_account_deletion">Запрос удаления аккаунта</string>
     <string name="reshare_not_allowed">Повторное открытие доступа запрещено</string>
     <string name="resharing_is_not_allowed">Повторное открытие доступа запрещено</string>
     <string name="resized_image_not_possible_download">Оптимизированное изображение отсутствует. Скачать изображение исходного размера?</string>

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

@@ -558,6 +558,7 @@
     <string name="rename_dialog_title">Inserta unu nùmene nou</string>
     <string name="rename_local_fail_msg">No at fatu a torrare a numenare sa còpia locale, proa cun un\'àteru nùmene</string>
     <string name="rename_server_fail_msg">Impossìbile a torrare a numenare, su nùmene esistit giai</string>
+    <string name="request_account_deletion">Rechede de cantzellare su contu</string>
     <string name="reshare_not_allowed">Non faghet a torrare a cumpartzire</string>
     <string name="resharing_is_not_allowed">Non faghet a torrare a cumpartzire</string>
     <string name="resized_image_not_possible_download">Impossìbile a modificare sa mannària de s\'immàgine. Dda boles iscarrigare intrea?</string>

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

@@ -613,6 +613,7 @@
     <string name="rename_dialog_title">Zadajte nové meno</string>
     <string name="rename_local_fail_msg">Nepodarilo sa premenovať lokálnu kópiu, skúste iné meno</string>
     <string name="rename_server_fail_msg">Premenovanie sa nepodarilo, meno sa už používa</string>
+    <string name="request_account_deletion">Žiadosť o zmazanie účtu</string>
     <string name="reshare_not_allowed">Opätovné sprístupňovanie nie je povolené</string>
     <string name="resharing_is_not_allowed">Sprístupnenie už sprístupnenej položky nie je povolené</string>
     <string name="resized_image_not_possible_download">Obrázok v inom rozlíšení nedostupný.  Stiahnuť pôvodný obrázok?</string>

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

@@ -18,6 +18,7 @@
     <string name="actionbar_copy">Kopiraj</string>
     <string name="actionbar_mkdir">Nova mapa</string>
     <string name="actionbar_move">Premakni</string>
+    <string name="actionbar_move_or_copy">Premakni ali Kopiraj</string>
     <string name="actionbar_open_with">Odpri s programom</string>
     <string name="actionbar_search">Iskanje</string>
     <string name="actionbar_see_details">Podrobnosti</string>
@@ -159,6 +160,7 @@
     <string name="conflict_message_description">Če izberete obe različici, bo k imenu krajevne datoteke dodana številka.</string>
     <string name="conflict_server_file">Strežniška datoteka</string>
     <string name="contact_backup_title">Varnostna kopija stikov</string>
+    <string name="contact_no_permission">Potrebno je dovoljeno do stikov.</string>
     <string name="contactlist_item_icon">Ikona uporabnika za seznam stikov</string>
     <string name="contactlist_no_permission">Ni ustreznih dovoljenj, uvoz je prekinjen.</string>
     <string name="contacts">Stiki</string>
@@ -204,6 +206,7 @@
     <string name="did_not_check_for_dupes">Ne preverjaj za podvojene.</string>
     <string name="digest_algorithm_not_available">Ta algoritem na tej napravi ni podprt.</string>
     <string name="direct_login_failed">Prijava prek neposredne povezave je spodletela.</string>
+    <string name="direct_login_text">Prijava z %1$s v %2$s</string>
     <string name="disable_new_media_folder_detection_notifications">Onemogoči</string>
     <string name="dismiss">Opusti</string>
     <string name="dismiss_notification_description">Opusti obvestilo</string>
@@ -253,7 +256,10 @@
     <string name="ecosystem_apps_display_more">Več</string>
     <string name="ecosystem_apps_display_notes">Beležke</string>
     <string name="ecosystem_apps_display_talk">Pogovor Talk</string>
+    <string name="ecosystem_apps_more">Več Nexcloud Aplikacij</string>
     <string name="ecosystem_apps_notes">Nextcloud Beležke</string>
+    <string name="ecosystem_apps_talk">Nextcloud Talk</string>
+    <string name="email_pick_failed">E-poštnega naslova ni bilo mogoče izbrati.</string>
     <string name="encrypted">Nastavi kot šifrirano</string>
     <string name="end_to_end_encryption_confirm_button">Nastavitev šifriranja</string>
     <string name="end_to_end_encryption_decrypting">Poteka odšifriranje…</string>
@@ -416,8 +422,14 @@
     <string name="icon_for_empty_list">Ikona za prazen seznam</string>
     <string name="icon_of_dashboard_widget">Ikona gradnika nadzorne plošče</string>
     <string name="icon_of_widget_entry">Ikona vnosa gradnikov</string>
+    <string name="image_editor_file_edited_suffix">urejeno</string>
+    <string name="image_editor_flip_horizontal">Obrni vodoravno</string>
+    <string name="image_editor_flip_vertical">Obrni navpično</string>
+    <string name="image_editor_rotate_ccw">Zavrti v levo</string>
+    <string name="image_editor_rotate_cw">Zavrti v desno</string>
     <string name="image_editor_unable_to_edit_image">Slike ni mogoče urediti.</string>
     <string name="image_preview_filedetails">Podrobnosti datoteke</string>
+    <string name="image_preview_image_taking_conditions">Pogoji fotografiranja</string>
     <string name="image_preview_unit_fnumber">ƒ/%s</string>
     <string name="image_preview_unit_iso">ISO %s</string>
     <string name="image_preview_unit_megapixel">%s MP</string>
@@ -450,6 +462,7 @@
     <string name="locked_by_app">Zaklenjeno s strani %1$s</string>
     <string name="log_send_mail_subject">%1$s dnevniki programa</string>
     <string name="log_send_no_mail_app">Ni nameščenega programa za pošiljanje dnevnikov. Namestiti je treba program za elektronsko pošto.</string>
+    <string name="logged_in_as">Prijavljen kot %1$s</string>
     <string name="login">Prijava</string>
     <string name="login_url_helper_text">Povezava do spletnega vmesnika %1$s, ki se odpre v brskalniku.</string>
     <string name="logs_menu_delete">Izbriši dnevnike</string>
@@ -502,6 +515,7 @@
     <string name="no_calendar_exists">Ni nobenega koledarja</string>
     <string name="no_email_app_available">Ni nameščenega programa, ki upravlja elektronskimi naslovi.</string>
     <string name="no_items">Ni predmetov</string>
+    <string name="no_map_app_availble">Ni nameščenega programa za odpiranje zemljevidov</string>
     <string name="no_mutliple_accounts_allowed">Dovoljen je le en račun</string>
     <string name="no_pdf_app_available">Ni nameščenega programa za odpiranje datotek PDF</string>
     <string name="no_send_app">Na voljo ni nobenega programa za pošiljanje izbranih datotek</string>
@@ -588,6 +602,7 @@
     <string name="prefs_imprint">Natis</string>
     <string name="prefs_instant_behaviour_dialogTitle">Izvorna datoteka bo…</string>
     <string name="prefs_instant_behaviour_title">Izvorna datoteka bo…</string>
+    <string name="prefs_instant_upload_path_use_date_subfolders_summary">Shranjevanje v podmape glede na datum</string>
     <string name="prefs_instant_upload_path_use_subfolders_title">Uporabi podmape</string>
     <string name="prefs_instant_upload_subfolder_rule_title">Možnosti podmape</string>
     <string name="prefs_keys_exist">Dodaj celovito šifriranje E2E na to napravo</string>
@@ -604,6 +619,7 @@
     <string name="prefs_remove_e2e">Krajevno odstrani šifriranje</string>
     <string name="prefs_setup_e2e">Nastavi celovito šifriranje E2E</string>
     <string name="prefs_show_ecosystem_apps">Pokaži preklopnika programov</string>
+    <string name="prefs_show_ecosystem_apps_summary">Predlogi aplikacij Nextcloud v navigacijskem naslovu</string>
     <string name="prefs_show_hidden_files">Pokaži skrite datoteke</string>
     <string name="prefs_sourcecode">Pridobi izvorno kodo</string>
     <string name="prefs_storage_path">Mapa podatkovne shrambe</string>
@@ -632,6 +648,7 @@
     <string name="remote">(oddaljeno) </string>
     <string name="remote_file_fetch_failed">Iskanje datoteke je spodletelo!</string>
     <string name="remove_e2e">Na tej napravi lahko odstranite krajevno celovito šifriranje E2E</string>
+    <string name="remove_e2e_message">V tem odjemalcu lahko lokalno odstranite šifriranje E2E. Šifrirane datoteke bodo ostale na strežniku, vendar ne bodo več sinhronizirane s tem računalnikom.</string>
     <string name="remove_fail_msg">Brisanje je spodletelo</string>
     <string name="remove_notification_failed">Odstranjevanje obvestil je spodletelo.</string>
     <string name="remove_push_notification">Odstrani</string>
@@ -639,6 +656,7 @@
     <string name="rename_dialog_title">Vnesite novo ime</string>
     <string name="rename_local_fail_msg">Ni mogoče preimenovati krajevne kopije. Poskusite vpisati drugačno ime.</string>
     <string name="rename_server_fail_msg">Preimenovanje ni mogoče. Ime je že uporabljeno.</string>
+    <string name="request_account_deletion">Zahtevaj izbris računa</string>
     <string name="reshare_not_allowed">Osveževanje ni dovoljena</string>
     <string name="resharing_is_not_allowed">Osveževanje ni dovoljeno</string>
     <string name="resized_image_not_possible_download">Slika prilagojene velikosti ni na voljo. Ali želite prejeti sliko polne velikosti?</string>
@@ -669,12 +687,14 @@
     <string name="select_template">Izbor predloge</string>
     <string name="send">Pošlji</string>
     <string name="send_note">Pošlji sporočilo prejemniku</string>
+    <string name="send_share">Pošlji souporabo</string>
     <string name="sendbutton_description">Ikona gumba za pošiljanje</string>
     <string name="set_as">Nastavi kot</string>
     <string name="set_note">Nastavi sporočilo</string>
     <string name="set_picture_as">Uporabi sliko kot</string>
     <string name="set_status">Nastavi stanje</string>
     <string name="set_status_message">Nastavi sporočilo stanja</string>
+    <string name="setup_e2e">Med nastavitvijo šifriranja E2E boste prejeli naključno 12-mestno sporočilo, ki ga boste morali odpreti na drugih napravah. To bo shranjeno samo na tej napravi in ga je mogoče ponovno prikazati na tem zaslonu. Prosimo, zabeležite ga na varnem mestu!</string>
     <string name="share">Souporaba</string>
     <string name="share_copy_link">Omogoči souporabo &amp; Kopiraj povezavo</string>
     <string name="share_dialog_title">Souporaba</string>
@@ -928,7 +948,9 @@
     <string name="wait_a_moment">Počakajte trenutek …</string>
     <string name="wait_checking_credentials">Poteka preverjanje shranjenih poveril</string>
     <string name="wait_for_tmp_copy_from_private_storage">Kopiranje datoteke iz zasebne shrambe</string>
+    <string name="webview_version_check_alert_dialog_message">Prosimo, posodobite aplikacijo Android System WebView za prijavo</string>
     <string name="webview_version_check_alert_dialog_positive_button_title">Posodobi</string>
+    <string name="webview_version_check_alert_dialog_title">Posodobite Android System WebView</string>
     <string name="what_s_new_image">Kaj je nova slika</string>
     <string name="whats_new_skip">Preskoči</string>
     <string name="whats_new_title">Novo v %1$s</string>
@@ -950,6 +972,12 @@
         <item quantity="few">Spodletelo je kopiranje %1$d datotek iz mape %2$s v</item>
         <item quantity="other">Spodletelo je kopiranje %1$d datotek iz mape %2$s v</item>
     </plurals>
+    <plurals name="wrote_n_events_to">
+        <item quantity="one">%1$d zapisan dogodek v %2$s</item>
+        <item quantity="two">%1$d zapisana dogodka v %2$s</item>
+        <item quantity="few">%1$d zapisanih dogodkov v %2$s</item>
+        <item quantity="other">%1$d zapisanih dogodkov v %2$s</item>
+    </plurals>
     <plurals name="created_n_uids_to">
         <item quantity="one">Ustvarjeno je %1$d novo določilo UID</item>
         <item quantity="two">Ustvarjeni sta %1$d novi določili UID</item>
@@ -974,6 +1002,24 @@
         <item quantity="few">Izvožene so %d datoteke.</item>
         <item quantity="other">Izvoženih je %d datotek.</item>
     </plurals>
+    <plurals name="export_failed">
+        <item quantity="one">Napaka pri izvažanju %d datoteke</item>
+        <item quantity="two">Napaka pri izvažanju %d datotek</item>
+        <item quantity="few">Napaka pri izvažanju %d datotek</item>
+        <item quantity="other">Napaka pri izvažanju %d datotek</item>
+    </plurals>
+    <plurals name="export_partially_failed">
+        <item quantity="one">Izvožena %d datoteka, ostale so bile preskočene zaradi napake</item>
+        <item quantity="two">Izvoženi %d datoteki, ostale so bile preskočene zaradi napake</item>
+        <item quantity="few">Izvoženih %d datotek, ostale so bile preskočene zaradi napake</item>
+        <item quantity="other">Izvoženih %d datotek, ostale so bile preskočene zaradi napake</item>
+    </plurals>
+    <plurals name="export_start">
+        <item quantity="one">Izvožena bo %d datoteka. Za podrobnosti glejte obvestilo.</item>
+        <item quantity="two">Izvožena bosta %d datoteki. Za podrobnosti glejte obvestilo.</item>
+        <item quantity="few">Izvoženih bo %d datotek. Za podrobnosti glejte obvestilo.</item>
+        <item quantity="other">Izvoženih bo %d datotek. Za podrobnosti glejte obvestilo.</item>
+    </plurals>
     <plurals name="file_list__footer__folder">
         <item quantity="one">%1$d mapa</item>
         <item quantity="two">%1$d mapi</item>

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

@@ -160,6 +160,7 @@
     <string name="conflict_message_description">Ако изаберете обе верзије, локални фајл имаће број придодат свом називу.</string>
     <string name="conflict_server_file">Серверски фајл</string>
     <string name="contact_backup_title">Резервна копија контаката</string>
+    <string name="contact_no_permission">Неопходна је дозвола контакта.</string>
     <string name="contactlist_item_icon">Икона корисника за листу контаката</string>
     <string name="contactlist_no_permission">Није дата дозвола. Ништа није увезено.</string>
     <string name="contacts">Контакти</string>
@@ -258,6 +259,7 @@
     <string name="ecosystem_apps_more">Још Nextcloud апликација</string>
     <string name="ecosystem_apps_notes">Некстклауд Белешке</string>
     <string name="ecosystem_apps_talk">Nextcloud Talk</string>
+    <string name="email_pick_failed">Није успело бирање и-мејл адресе.</string>
     <string name="encrypted">Постави као шифровано</string>
     <string name="end_to_end_encryption_confirm_button">Подесите шифровање</string>
     <string name="end_to_end_encryption_decrypting">Дешифрујем…</string>
@@ -648,12 +650,17 @@
     <string name="remove_e2e">Шифрирање од почетка-до-краја можете локално да уклоните на овом клијенту</string>
     <string name="remove_e2e_message">Шифрирање од почетка-до-краја можете локално да уклоните на овом клијенту. Шифрирани фајлови ће остати на серверу, али се више неће синхронизовати са овим компјутером.</string>
     <string name="remove_fail_msg">Брисање није успело</string>
+    <string name="remove_local_account">Уклони локални налог</string>
+    <string name="remove_local_account_details">Укњања локални налог са уређаја у брише све локалне фајлове</string>
     <string name="remove_notification_failed">Грешка при уклањању обавештења.</string>
     <string name="remove_push_notification">Уклони</string>
     <string name="remove_success_msg">Обрисано</string>
     <string name="rename_dialog_title">Унесите нов назив</string>
     <string name="rename_local_fail_msg">Не могу да преименујем локалну копију. Пробајте други назив</string>
     <string name="rename_server_fail_msg">Преименовање није могуће. Назив већ постоји</string>
+    <string name="request_account_deletion">Захтевајте брисање налога</string>
+    <string name="request_account_deletion_button">Захтев за брисање</string>
+    <string name="request_account_deletion_details">Захтев пружаоцу сервиса да неповратно обрише налог</string>
     <string name="reshare_not_allowed">Поновно дељење није дозвољено</string>
     <string name="resharing_is_not_allowed">Поновно дељење није дозвољено</string>
     <string name="resized_image_not_possible_download">Нема доступне умањене сличице. Скинути пуну слику?</string>

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

@@ -160,6 +160,7 @@
     <string name="conflict_message_description">Om du väljer båda versionerna kommer den lokala filen få ett nummer tillagt i filnamnet.</string>
     <string name="conflict_server_file">Serverfil</string>
     <string name="contact_backup_title">Backup av kontakter</string>
+    <string name="contact_no_permission">Rättighet till kontakt krävs.</string>
     <string name="contactlist_item_icon">Användarikon för kontaktlista</string>
     <string name="contactlist_no_permission">Ingen tillstått givet, ingen importerat!</string>
     <string name="contacts">Kontakter</string>
@@ -258,6 +259,7 @@
     <string name="ecosystem_apps_more">Fler Nextcloud-appar</string>
     <string name="ecosystem_apps_notes">Nextcloud anteckningar</string>
     <string name="ecosystem_apps_talk">Nextcloud Talk</string>
+    <string name="email_pick_failed">Det gick inte att välja e-postadress.</string>
     <string name="encrypted">Sätt som krypterad</string>
     <string name="end_to_end_encryption_confirm_button">Aktivera kryptering</string>
     <string name="end_to_end_encryption_decrypting">Dekrypterar…</string>
@@ -649,12 +651,17 @@
     <string name="remove_e2e">Du kan ta bort end-to-end-kryptering lokalt på denna klient</string>
     <string name="remove_e2e_message">Du kan ta bort end-to-end-kryptering lokalt på denna klienten. Krypterade filer kommer finnas kvar på servern, men kommer inte synkroniseras med denna enheten längre.</string>
     <string name="remove_fail_msg">Radering misslyckades</string>
+    <string name="remove_local_account">Ta bort lokalt konto</string>
+    <string name="remove_local_account_details">Ta bort kontot från enheten och radera alla lokala filer</string>
     <string name="remove_notification_failed">Kunde inte radera notifiering.</string>
     <string name="remove_push_notification">Ta bort</string>
     <string name="remove_success_msg">Borttagen</string>
     <string name="rename_dialog_title">Ange ett nytt namn</string>
     <string name="rename_local_fail_msg">Det gick inte att byta namn på lokal kopia, prova ett annat namn</string>
     <string name="rename_server_fail_msg">Namnbytning är inte möjligt, namnet är redan taget</string>
+    <string name="request_account_deletion">Begär att radera ditt konto</string>
+    <string name="request_account_deletion_button">Begäran om radering</string>
+    <string name="request_account_deletion_details">Begär permanent borttagning av konto av tjänsteleverantör</string>
     <string name="reshare_not_allowed">Dela vidare är inte tillåtet</string>
     <string name="resharing_is_not_allowed">Att dela på nytt är inte tillåtet</string>
     <string name="resized_image_not_possible_download">Ingen storleksändrad bild tillgänglig. Hämta hela bilden?</string>

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

@@ -493,6 +493,7 @@
     <string name="remove_push_notification">ลบออก</string>
     <string name="remove_success_msg">ลบแล้ว</string>
     <string name="rename_dialog_title">กรอกชื่อใหม่</string>
+    <string name="request_account_deletion">ขอลบบัญชี</string>
     <string name="reshare_not_allowed">ไม่อนุญาตให้แชร์ซ้ำ</string>
     <string name="resharing_is_not_allowed">ไม่อนุญาตให้แชร์ซ้ำ</string>
     <string name="scanQR_description">เข้าสู่ระบบผ่านคิวอาร์โค้ด</string>

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

@@ -160,6 +160,7 @@
     <string name="conflict_message_description">İki sürümü de saklamayı seçerseniz, yerel dosyanın adına bir numara eklenecek.</string>
     <string name="conflict_server_file">Sunucu dosyası</string>
     <string name="contact_backup_title">Kişiler yedeği</string>
+    <string name="contact_no_permission">Kişi izinleri gerekli.</string>
     <string name="contactlist_item_icon">Kişi listesi kullanıcı simgesi</string>
     <string name="contactlist_no_permission">Herhangi bir izin verilmemiş olduğundan hiçbir şey içe aktarılamadı.</string>
     <string name="contacts">Kişiler</string>
@@ -258,6 +259,7 @@
     <string name="ecosystem_apps_more">Diğer Nextcloud uygulamaları</string>
     <string name="ecosystem_apps_notes">Nextcloud Notlar</string>
     <string name="ecosystem_apps_talk">Nextcloud Sohbet</string>
+    <string name="email_pick_failed">E-posta adresi alınamadı.</string>
     <string name="encrypted">Şifrelensin</string>
     <string name="end_to_end_encryption_confirm_button">Şifreleme kurulumu</string>
     <string name="end_to_end_encryption_decrypting">Şifre çözülüyor …</string>
@@ -648,12 +650,14 @@
     <string name="remove_e2e">Bu istemciden uçtan uca şifrelemeyi yerel olarak kaldırabilirsiniz</string>
     <string name="remove_e2e_message">Bu istemcide yerel olarak uçtan uca şifrelemeyi kaldırabilirsiniz. Şifrelenmiş dosyalar sunucuda kalır, ancak artık bu bilgisayarla eşitlenmez.</string>
     <string name="remove_fail_msg">Silinemedi</string>
+    <string name="remove_local_account">Yerel hesabı sil</string>
     <string name="remove_notification_failed">Bildirim silinemedi.</string>
     <string name="remove_push_notification">Sil</string>
     <string name="remove_success_msg">Silindi</string>
     <string name="rename_dialog_title">Yeni bir ad yazın</string>
     <string name="rename_local_fail_msg">Yerel kopyanın adı değiştirilemedi. Lütfen başka bir ad deneyin</string>
     <string name="rename_server_fail_msg">Ad zaten kullanıldığından yeniden adlandırılamadı</string>
+    <string name="request_account_deletion">Hesabınızın silinmesini isteyin</string>
     <string name="reshare_not_allowed">Yeniden paylaşıma izin verilmiyor</string>
     <string name="resharing_is_not_allowed">Yeniden paylaşıma izin verilmiyor</string>
     <string name="resized_image_not_possible_download">Boyutu değiştirilmiş bir görsel yok. Tam boyuttaki görsel indirilsin mi?</string>
@@ -711,7 +715,7 @@
     <string name="share_link_optional_password_title">İsteğe bağlı olarak parola yazın</string>
     <string name="share_link_password_title">Bir parola yazın</string>
     <string name="share_link_with_label">Bağlantı paylaş (%1$s)</string>
-    <string name="share_no_expiration_date_label">Son kullanma tarihini ayarla</string>
+    <string name="share_no_expiration_date_label">Geçerlilik sonu tarihini ayarla</string>
     <string name="share_no_password_title">Parolayı ayarla</string>
     <string name="share_password_title">Parola korumalı</string>
     <string name="share_permission_can_edit">Düzenleyebilir</string>

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

@@ -160,6 +160,7 @@
     <string name="conflict_message_description">Якщо ви виберете обидві версії, то до назви локального файлу буде додано порядковий номер.</string>
     <string name="conflict_server_file">Файл у хмарі</string>
     <string name="contact_backup_title">Резервне копіювання контактів</string>
+    <string name="contact_no_permission">Потрібний доступ до контактів.</string>
     <string name="contactlist_item_icon">Іконка списку контактів</string>
     <string name="contactlist_no_permission">Не надано дозволів, дані не імпортовано</string>
     <string name="contacts">Контакти</string>
@@ -639,12 +640,17 @@
     <string name="remove_e2e">Ви можете вилучити наскрізне шифрування на пристрої на цьому клієнті</string>
     <string name="remove_e2e_message">Ви можете вилучити наскрізне шифрування на пристрої на цьому клієнті. Зашифровані файли залишатимуться на сервері, але більше не синхронізуватимуться з цим комп\'ютером.</string>
     <string name="remove_fail_msg">Помилка під час вилучення</string>
+    <string name="remove_local_account">Вилучити обліковий запис на пристрої</string>
+    <string name="remove_local_account_details">Вилучити обліковий запис з пристрою та всі файли на пристрої</string>
     <string name="remove_notification_failed">Неможливо зняти сповіщення.</string>
     <string name="remove_push_notification">Вилучити</string>
     <string name="remove_success_msg">Вилучено</string>
     <string name="rename_dialog_title">Введіть нове ім\'я</string>
     <string name="rename_local_fail_msg">Неможливо перейменувати локальну копію, спробуйте інше ім\'я</string>
     <string name="rename_server_fail_msg">Неможливо перейменувати, таке ім\'я уже існує</string>
+    <string name="request_account_deletion">Запит на вилучення облікового запису</string>
+    <string name="request_account_deletion_button">Запит на вилучення</string>
+    <string name="request_account_deletion_details">Запит на вилучення облікового запису з боку постачальника послуг</string>
     <string name="reshare_not_allowed">Надання спільного доступу іншим не дозволяється</string>
     <string name="resharing_is_not_allowed">Надання спільного доступу іншим не дозволяється</string>
     <string name="resized_image_not_possible_download">Відсутнє зображення зі зменшеними розмірами. Звантажити повне зображення?</string>
@@ -725,7 +731,7 @@
     <string name="shared_icon_share">поділитися</string>
     <string name="shared_icon_shared">надано доступ</string>
     <string name="shared_icon_shared_via_link">доступ надано за посиланням</string>
-    <string name="shared_with_you_by">%1$s поділився з вами</string>
+    <string name="shared_with_you_by">%1$s поділив(-ла-)ся з вами</string>
     <string name="sharee_add_failed">Помилка додавання користувача, з яким ви хочете поділитися</string>
     <string name="show_images">Показувати зображення</string>
     <string name="show_video">Показувати відео</string>
@@ -787,7 +793,7 @@
     <string name="sub_folder_rule_month">Рік/місяць</string>
     <string name="sub_folder_rule_year">Рік</string>
     <string name="subject_shared_with_you">Вам було надано доступ до \"%1$s\"</string>
-    <string name="subject_user_shared_with_you">%1$s поділився %2$s з вами</string>
+    <string name="subject_user_shared_with_you">%1$s поділив(-ла-)ся %2$s з вами</string>
     <string name="subtitle_photos_only">Лише зображення</string>
     <string name="subtitle_photos_videos">Зображення та відео</string>
     <string name="subtitle_videos_only">Лише відео</string>

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

@@ -160,6 +160,7 @@
     <string name="conflict_message_description">如果您选择两个版本,则本地文件的名称后面将附加一个数字。</string>
     <string name="conflict_server_file">服务器文件</string>
     <string name="contact_backup_title">联系人备份</string>
+    <string name="contact_no_permission">需要联系人权限</string>
     <string name="contactlist_item_icon">联系人列表的用户图标</string>
     <string name="contactlist_no_permission">未授予权限,没有文件被导入</string>
     <string name="contacts">联系人</string>
@@ -258,6 +259,7 @@
     <string name="ecosystem_apps_more">更多Nextcloud应用</string>
     <string name="ecosystem_apps_notes">Nextcloud 笔记</string>
     <string name="ecosystem_apps_talk">Nextcloud Talk</string>
+    <string name="email_pick_failed">未能选择电子邮箱地址</string>
     <string name="encrypted">设置为加密</string>
     <string name="end_to_end_encryption_confirm_button">设置加密</string>
     <string name="end_to_end_encryption_decrypting">正在解密…</string>
@@ -648,12 +650,17 @@
     <string name="remove_e2e">您可以在该客户端上本地删除端对端加密</string>
     <string name="remove_e2e_message">您可以在该客户端上本地删除端对端加密。加密文件将保留在服务器上,但不会再同步到该电脑。</string>
     <string name="remove_fail_msg">删除失败</string>
+    <string name="remove_local_account">移除本地帐户</string>
+    <string name="remove_local_account_details">从设备中移除账户并删除所有本地文件</string>
     <string name="remove_notification_failed">移除通知失败</string>
     <string name="remove_push_notification">移除</string>
     <string name="remove_success_msg">已删除</string>
     <string name="rename_dialog_title">输入一个新的名称</string>
     <string name="rename_local_fail_msg">本地副本无法重命名,尝试其他名称</string>
     <string name="rename_server_fail_msg">无法重命名,名字已经被占用</string>
+    <string name="request_account_deletion">请求删除账号</string>
+    <string name="request_account_deletion_button">请求删除</string>
+    <string name="request_account_deletion_details">请求服务商永久删除账户</string>
     <string name="reshare_not_allowed">不允许再次共享</string>
     <string name="resharing_is_not_allowed">不允许二次共享</string>
     <string name="resized_image_not_possible_download">重整大小的图片不可用。下载完整图片?</string>

+ 10 - 0
app/src/main/res/values-zh-rHK/strings.xml

@@ -18,6 +18,7 @@
     <string name="actionbar_copy">複製</string>
     <string name="actionbar_mkdir">新資料夾</string>
     <string name="actionbar_move">移動</string>
+    <string name="actionbar_move_or_copy">移動或複製</string>
     <string name="actionbar_open_with">開啟方式</string>
     <string name="actionbar_search">搜尋</string>
     <string name="actionbar_see_details">詳細資料</string>
@@ -159,6 +160,7 @@
     <string name="conflict_message_description">若您同時選擇兩個版本,近端的檔案會在檔名後附加編號。</string>
     <string name="conflict_server_file">伺服器檔案</string>
     <string name="contact_backup_title">聯絡人備份</string>
+    <string name="contact_no_permission">需要聯絡人權限。</string>
     <string name="contactlist_item_icon">聯絡清單的用戶圖示</string>
     <string name="contactlist_no_permission">匯入失敗,權限不足。</string>
     <string name="contacts">通訊錄</string>
@@ -257,6 +259,7 @@
     <string name="ecosystem_apps_more">更多 Nextcloud 應用程式</string>
     <string name="ecosystem_apps_notes">Nextcloud 筆記</string>
     <string name="ecosystem_apps_talk">Nextcloud Talk</string>
+    <string name="email_pick_failed">無法挑選電郵地址。</string>
     <string name="encrypted">設為已加密的</string>
     <string name="end_to_end_encryption_confirm_button">設定加密</string>
     <string name="end_to_end_encryption_decrypting">解密中…</string>
@@ -647,12 +650,17 @@
     <string name="remove_e2e">您可以在此客戶端上本地刪除端到端加密</string>
     <string name="remove_e2e_message">您可以在此客戶端上本地刪除端到端加密。加密檔案將保留在伺服器上,但不會再同步到此電腦。</string>
     <string name="remove_fail_msg">刪除失敗</string>
+    <string name="remove_local_account">移除近端賬戶</string>
+    <string name="remove_local_account_details">從裝置中刪除賬戶並刪除所有近端檔案</string>
     <string name="remove_notification_failed">移除通知失敗</string>
     <string name="remove_push_notification">移除</string>
     <string name="remove_success_msg">已刪除</string>
     <string name="rename_dialog_title">輸入新名稱</string>
     <string name="rename_local_fail_msg">無法重新命名近端複本,請試用不同名稱</string>
     <string name="rename_server_fail_msg">不可重新命名,名稱已存在</string>
+    <string name="request_account_deletion">請求賬戶刪除</string>
+    <string name="request_account_deletion_button">請求刪除</string>
+    <string name="request_account_deletion_details">請求服務提供者永久刪除賬戶</string>
     <string name="reshare_not_allowed">不允許重新分享</string>
     <string name="resharing_is_not_allowed">不允許重新分享</string>
     <string name="resized_image_not_possible_download">沒有可用調整過的圖像,下載完整圖像?</string>
@@ -944,7 +952,9 @@
     <string name="wait_a_moment">請稍候…</string>
     <string name="wait_checking_credentials">檢查儲存的身分驗證</string>
     <string name="wait_for_tmp_copy_from_private_storage">從私有儲存空間複製檔案中</string>
+    <string name="webview_version_check_alert_dialog_message">請更新 Android System WebView 應用程式以進行登入</string>
     <string name="webview_version_check_alert_dialog_positive_button_title">更新</string>
+    <string name="webview_version_check_alert_dialog_title">更新 Android System WebView</string>
     <string name="what_s_new_image">有什麼新圖像?</string>
     <string name="whats_new_skip">略過</string>
     <string name="whats_new_title">新增到 %1$s </string>

+ 8 - 0
app/src/main/res/values-zh-rTW/strings.xml

@@ -160,6 +160,7 @@
     <string name="conflict_message_description">若您同時選擇兩個版本,本機的檔案會在檔名後附加編號。</string>
     <string name="conflict_server_file">伺服器檔案</string>
     <string name="contact_backup_title">聯絡人備份</string>
+    <string name="contact_no_permission">需要聯絡人權限。</string>
     <string name="contactlist_item_icon">聯絡人列表的使用者圖示</string>
     <string name="contactlist_no_permission">匯入失敗,權限不足。</string>
     <string name="contacts">聯絡人</string>
@@ -258,6 +259,7 @@
     <string name="ecosystem_apps_more">更多 Nextcloud 應用程式</string>
     <string name="ecosystem_apps_notes">Nextcloud Notes</string>
     <string name="ecosystem_apps_talk">Nextcloud Talk</string>
+    <string name="email_pick_failed">挑選電子郵件地址失敗。</string>
     <string name="encrypted">設為已加密的</string>
     <string name="end_to_end_encryption_confirm_button">設定加密</string>
     <string name="end_to_end_encryption_decrypting">正在解密……</string>
@@ -648,12 +650,17 @@
     <string name="remove_e2e">您可以在此客戶端上本機移除端到端加密</string>
     <string name="remove_e2e_message">您可以在此客戶端上移除本機端到端加密。已加密的檔案將會保留在伺服器上,但不會再同步到此電腦。</string>
     <string name="remove_fail_msg">刪除失敗</string>
+    <string name="remove_local_account">移除本機帳號</string>
+    <string name="remove_local_account_details">從裝置移除帳號並刪除所有本機檔案</string>
     <string name="remove_notification_failed">移除通知失敗</string>
     <string name="remove_push_notification">移除</string>
     <string name="remove_success_msg">已刪除</string>
     <string name="rename_dialog_title">輸入新名稱</string>
     <string name="rename_local_fail_msg">無法重新命名本機副本,請嘗試不同的名稱</string>
     <string name="rename_server_fail_msg">無法重新命名,該名稱已被使用</string>
+    <string name="request_account_deletion">請求刪除帳號</string>
+    <string name="request_account_deletion_button">請求刪除</string>
+    <string name="request_account_deletion_details">請求服務提供者永久刪除帳號</string>
     <string name="reshare_not_allowed">不允許重新分享</string>
     <string name="resharing_is_not_allowed">不允許重新分享</string>
     <string name="resized_image_not_possible_download">沒有可用調整過的圖片。下載完整圖片?</string>
@@ -877,6 +884,7 @@
     <string name="upload_lock_failed">鎖定資料夾失敗</string>
     <string name="upload_old_android">加密功能僅適用於 Android 5.0 及更新版本</string>
     <string name="upload_query_move_foreign_files">空間不足以將選擇的檔案複製到 %1$s 資料夾,是否要改成移動它們?</string>
+    <string name="upload_quota_exceeded">超過儲存空間配額</string>
     <string name="upload_scan_doc_upload">使用相機掃描文件</string>
     <string name="upload_sync_conflict">同步發生衝突,請手動處理</string>
     <string name="upload_unknown_error">未知的錯誤</string>

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

@@ -129,8 +129,12 @@
     <string name="common_skip">Skip</string>
     <string name="common_copy">Copy</string>
     <string name="about_title">About</string>
+    <string name="remove_local_account">Remove local account</string>
+    <string name="remove_local_account_details">Remove account from device and delete all local files</string>
+    <string name="request_account_deletion">Request account deletion</string>
+    <string name="request_account_deletion_button">Request deletion</string>
+    <string name="request_account_deletion_details">Request permanent deletion of account by service provider</string>
     <string name="delete_account">Remove account</string>
-    <string name="delete_account_warning">Remove account %s and delete all local files?\n\nDeletion cannot be undone.</string>
     <string name="avatar">Avatar</string>
     <string name="active_user">Active user</string>
     <string name="upload_chooser_title">Upload from…</string>
@@ -827,6 +831,7 @@
     <string name="upload_sync_conflict">Sync conflict, please resolve manually</string>
     <string name="upload_cannot_create_file">Cannot create local file</string>
     <string name="upload_local_storage_not_copied">File could not be copied to local storage</string>
+    <string name="upload_quota_exceeded">Storage quota exceeded</string>
     <string name="host_not_available">Server not available</string>
     <string name="delete_entries">Delete entries</string>
     <string name="dismiss_notification_description">Dismiss notification</string>

+ 1 - 1
build.gradle

@@ -1,6 +1,6 @@
 buildscript {
     ext {
-        androidPluginVersion = '8.1.1'
+        androidPluginVersion = '8.1.4'
         appCompatVersion = '1.6.1'
         jacoco_version = '0.8.10'
         kotlin_version = '1.8.22'

部分文件因为文件数量过多而无法显示