ソースを参照

Merge master

Signed-off-by: alperozturk <alper_ozturk@proton.me>
alperozturk 1 年間 前
コミット
8a60b0e0f1
30 ファイル変更134 行追加117 行削除
  1. 1 1
      .github/workflows/assembleFlavors.yml
  2. 1 1
      .github/workflows/check.yml
  3. 2 2
      .github/workflows/codeql.yml
  4. 1 1
      .github/workflows/detectWrongSettings.yml
  5. 1 1
      .github/workflows/qa.yml
  6. 1 1
      .github/workflows/scorecard.yml
  7. 1 1
      .github/workflows/screenShotTest.yml
  8. 1 1
      .github/workflows/unit-tests.yml
  9. BIN
      app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRenameFileDialog.png
  10. BIN
      app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailFragmentStaticServerIT_showFileDetailDetailsFragment.png
  11. 1 1
      app/src/androidTest/java/com/owncloud/android/AbstractIT.java
  12. 14 4
      app/src/androidTest/java/com/owncloud/android/AbstractOnServerIT.java
  13. 2 26
      app/src/androidTest/java/com/owncloud/android/UploadIT.java
  14. 8 0
      app/src/androidTest/java/com/owncloud/android/ui/LoginIT.kt
  15. 9 1
      app/src/main/java/com/nextcloud/client/preferences/AppPreferencesImpl.java
  16. 1 1
      app/src/main/java/com/owncloud/android/ui/dialog/ChooseRichDocumentsTemplateDialogFragment.java
  17. 1 1
      app/src/main/java/com/owncloud/android/ui/dialog/ChooseTemplateDialogFragment.kt
  18. 1 1
      app/src/main/java/com/owncloud/android/ui/dialog/CreateFolderDialogFragment.java
  19. 1 1
      app/src/main/java/com/owncloud/android/ui/dialog/NoteDialogFragment.java
  20. 68 54
      app/src/main/java/com/owncloud/android/ui/dialog/RenameFileDialogFragment.java
  21. 1 1
      app/src/main/java/com/owncloud/android/ui/dialog/RenamePublicShareDialogFragment.java
  22. 1 1
      app/src/main/java/com/owncloud/android/ui/dialog/SharePasswordDialogFragment.java
  23. 10 16
      app/src/main/java/com/owncloud/android/utils/KeyboardUtils.kt
  24. 1 0
      app/src/main/res/values-ar/strings.xml
  25. 1 0
      app/src/main/res/values-b+en+001/strings.xml
  26. 1 0
      app/src/main/res/values-bg-rBG/strings.xml
  27. 1 0
      app/src/main/res/values-br/strings.xml
  28. 1 0
      app/src/main/res/values-ca/strings.xml
  29. 1 0
      app/src/main/res/values-da/strings.xml
  30. 1 0
      app/src/main/res/values-el/strings.xml

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

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

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

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

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

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

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

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

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

@@ -22,7 +22,7 @@ jobs:
             -   uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v3
                 if: ${{ steps.check-secrets.outputs.ok == 'true' }}
             -   name: set up JDK 17
-                uses: actions/setup-java@cd89f46ac9d01407894225f350157564c9c7cee2 # v3
+                uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # 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@d90b8d79de6dc1f58e83a1499aa58d6c93dc28de # v2.22.2
+        uses: github/codeql-action/upload-sarif@0116bc2df50751f9724a2e35ef1f24d22f90e4e1 # v2.22.3
         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@cd89f46ac9d01407894225f350157564c9c7cee2 # v3
+            -   uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3
                 with:
                     distribution: "temurin"
                     java-version: 17

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

@@ -20,7 +20,7 @@ jobs:
         steps:
             -   uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
             -   name: Set up JDK 17
-                uses: actions/setup-java@cd89f46ac9d01407894225f350157564c9c7cee2 # v3.12.0
+                uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3.13.0
                 with:
                     distribution: "temurin"
                     java-version: 17

BIN
app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRenameFileDialog.png


BIN
app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailFragmentStaticServerIT_showFileDetailDetailsFragment.png


+ 1 - 1
app/src/androidTest/java/com/owncloud/android/AbstractIT.java

@@ -314,7 +314,7 @@ public abstract class AbstractIT {
         return currentActivity;
     }
 
-    protected void shortSleep() {
+    protected static void shortSleep() {
         try {
             Thread.sleep(2000);
         } catch (InterruptedException e) {

+ 14 - 4
app/src/androidTest/java/com/owncloud/android/AbstractOnServerIT.java

@@ -135,10 +135,20 @@ public abstract class AbstractOnServerIT extends AbstractIT {
                                    .isSuccess());
                 }
 
-                assertTrue(new RemoveFileRemoteOperation(remoteFile.getRemotePath())
-                               .execute(client)
-                               .isSuccess()
-                          );
+                boolean removeResult = false;
+                for (int i = 0; i < 5; i++) {
+                    removeResult = new RemoveFileRemoteOperation(remoteFile.getRemotePath())
+                        .execute(client)
+                        .isSuccess();
+                    
+                    if (removeResult) {
+                        break;
+                    }
+
+                    shortSleep();
+                }
+
+                assertTrue(removeResult);
             }
         }
     }

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

@@ -41,7 +41,6 @@ import com.owncloud.android.operations.RemoveFileOperation;
 import com.owncloud.android.operations.UploadFileOperation;
 import com.owncloud.android.utils.FileStorageUtils;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -106,29 +105,6 @@ public class UploadIT extends AbstractOnServerIT {
         createDummyFiles();
     }
 
-    @After
-    public void after() {
-        RemoteOperationResult result = new RefreshFolderOperation(getStorageManager().getFileByPath("/"),
-                                                                  System.currentTimeMillis() / 1000L,
-                                                                  false,
-                                                                  true,
-                                                                  getStorageManager(),
-                                                                  user,
-                                                                  targetContext)
-            .execute(client);
-
-        // cleanup only if folder exists
-        if (result.isSuccess() && getStorageManager().getFileByDecryptedRemotePath(FOLDER) != null) {
-            new RemoveFileOperation(getStorageManager().getFileByDecryptedRemotePath(FOLDER),
-                                    false,
-                                    user,
-                                    false,
-                                    targetContext,
-                                    getStorageManager())
-                .execute(client);
-        }
-    }
-
     @Test
     public void testEmptyUpload() {
         OCUpload ocUpload = new OCUpload(FileStorageUtils.getTemporalPath(account.name) + "/empty.txt",
@@ -529,8 +505,8 @@ public class UploadIT extends AbstractOnServerIT {
 
         assertNotNull(ocFile);
         assertEquals(remotePath, ocFile.getRemotePath());
-        assertEquals(new ImageDimension(451f, 529f), ocFile.getImageDimension());
-        assertEquals(new GeoLocation(49.99679166666667, 8.67198611111111), ocFile.getGeoLocation());
+        assertEquals(new ImageDimension(300f, 200f), ocFile.getImageDimension());
+        assertEquals(new GeoLocation(64, -46), ocFile.getGeoLocation());
     }
 
     private void verifyStoragePath(OCFile file) {

+ 8 - 0
app/src/androidTest/java/com/owncloud/android/ui/LoginIT.kt

@@ -20,6 +20,7 @@
  */
 package com.owncloud.android.ui
 
+import android.os.Build
 import androidx.test.core.app.ActivityScenario
 import androidx.test.espresso.Espresso
 import androidx.test.espresso.action.ViewActions
@@ -28,6 +29,7 @@ import androidx.test.espresso.web.sugar.Web
 import androidx.test.espresso.web.webdriver.DriverAtoms
 import androidx.test.espresso.web.webdriver.Locator
 import androidx.test.filters.LargeTest
+import androidx.test.filters.SdkSuppress
 import androidx.test.platform.app.InstrumentationRegistry
 import com.nextcloud.client.account.UserAccountManager
 import com.nextcloud.client.account.UserAccountManagerImpl
@@ -59,6 +61,12 @@ class LoginIT : AbstractIT() {
     @Test
     @Throws(InterruptedException::class)
     @Suppress("MagicNumber", "SwallowedException")
+
+    /**
+     * The CI/CD pipeline is encountering issues related to the Android version for this functionality.
+     * Therefore the test will only be executed on Android versions 10 and above.
+     */
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q)
     fun login() {
         val arguments = InstrumentationRegistry.getArguments()
         val baseUrl = arguments.getString("TEST_SERVER_URL")!!

+ 9 - 1
app/src/main/java/com/nextcloud/client/preferences/AppPreferencesImpl.java

@@ -26,6 +26,7 @@ package com.nextcloud.client.preferences;
 import android.annotation.SuppressLint;
 import android.content.Context;
 import android.content.SharedPreferences;
+import android.content.res.Configuration;
 
 import com.google.gson.Gson;
 import com.nextcloud.appReview.AppReviewShownModel;
@@ -437,7 +438,14 @@ public final class AppPreferencesImpl implements AppPreferences {
 
     @Override
     public boolean isDarkModeEnabled() {
-        return getDarkThemeMode() == DarkMode.DARK;
+        DarkMode mode = getDarkThemeMode();
+
+        if (mode == DarkMode.SYSTEM) {
+            int currentNightMode = context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
+            return currentNightMode == Configuration.UI_MODE_NIGHT_YES;
+        }
+
+        return mode == DarkMode.DARK;
     }
 
     @Override

+ 1 - 1
app/src/main/java/com/owncloud/android/ui/dialog/ChooseRichDocumentsTemplateDialogFragment.java

@@ -138,7 +138,7 @@ public class ChooseRichDocumentsTemplateDialogFragment extends DialogFragment im
     @Override
     public void onResume() {
         super.onResume();
-        keyboardUtils.showKeyboardForEditText(binding.filename);
+        keyboardUtils.showKeyboardForEditText(requireDialog().getWindow(), binding.filename);
     }
 
     @NonNull

+ 1 - 1
app/src/main/java/com/owncloud/android/ui/dialog/ChooseTemplateDialogFragment.kt

@@ -119,7 +119,7 @@ class ChooseTemplateDialogFragment : DialogFragment(), View.OnClickListener, Tem
 
     override fun onResume() {
         super.onResume()
-        keyboardUtils.showKeyboardForEditText(binding.filename)
+        keyboardUtils.showKeyboardForEditText(dialog?.window, binding.filename)
     }
 
     override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {

+ 1 - 1
app/src/main/java/com/owncloud/android/ui/dialog/CreateFolderDialogFragment.java

@@ -116,7 +116,7 @@ public class CreateFolderDialogFragment
         super.onResume();
 
         bindButton();
-        keyboardUtils.showKeyboardForEditText(binding.userInput);
+        keyboardUtils.showKeyboardForEditText(requireDialog().getWindow(), binding.userInput);
     }
 
     @NonNull

+ 1 - 1
app/src/main/java/com/owncloud/android/ui/dialog/NoteDialogFragment.java

@@ -90,7 +90,7 @@ public class NoteDialogFragment extends DialogFragment implements DialogInterfac
     @Override
     public void onResume() {
         super.onResume();
-        keyboardUtils.showKeyboardForEditText(binding.noteText);
+        keyboardUtils.showKeyboardForEditText(requireDialog().getWindow(), binding.noteText);
     }
 
     @NonNull

+ 68 - 54
app/src/main/java/com/owncloud/android/ui/dialog/RenameFileDialogFragment.java

@@ -34,8 +34,8 @@ import android.text.TextUtils;
 import android.text.TextWatcher;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.widget.Button;
 
+import com.google.android.material.button.MaterialButton;
 import com.google.android.material.dialog.MaterialAlertDialogBuilder;
 import com.google.common.collect.Sets;
 import com.nextcloud.client.di.Injectable;
@@ -65,7 +65,7 @@ import androidx.fragment.app.DialogFragment;
  * Triggers the rename operation when name is confirmed.
  */
 public class RenameFileDialogFragment
-    extends DialogFragment implements DialogInterface.OnClickListener, Injectable {
+    extends DialogFragment implements DialogInterface.OnClickListener, TextWatcher, Injectable {
 
     private static final String ARG_TARGET_FILE = "TARGET_FILE";
     private static final String ARG_PARENT_FOLDER = "PARENT_FOLDER";
@@ -76,8 +76,8 @@ public class RenameFileDialogFragment
 
     private EditBoxDialogBinding binding;
     private OCFile mTargetFile;
-    private Button positiveButton;
-
+    private MaterialButton positiveButton;
+    private Set<String> fileNames;
 
     /**
      * Public factory method to create new RenameFileDialogFragment instances.
@@ -97,20 +97,13 @@ public class RenameFileDialogFragment
     @Override
     public void onStart() {
         super.onStart();
-
-        AlertDialog alertDialog = (AlertDialog) getDialog();
-
-        if (alertDialog != null) {
-            positiveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
-            viewThemeUtils.platform.colorTextButtons(positiveButton,
-                                                     alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL));
-        }
+        initAlertDialog();
     }
 
     @Override
     public void onResume() {
         super.onResume();
-        keyboardUtils.showKeyboardForEditText(binding.userInput);
+        keyboardUtils.showKeyboardForEditText(requireDialog().getWindow(), binding.userInput);
     }
 
     @NonNull
@@ -133,62 +126,46 @@ public class RenameFileDialogFragment
 
         OCFile parentFolder = requireArguments().getParcelable(ARG_PARENT_FOLDER);
         List<OCFile> folderContent = fileDataStorageManager.getFolderContent(parentFolder, false);
-        Set<String> fileNames = Sets.newHashSetWithExpectedSize(folderContent.size());
+        fileNames = Sets.newHashSetWithExpectedSize(folderContent.size());
 
         for (OCFile file : folderContent) {
             fileNames.add(file.getFileName());
         }
 
         // Add TextChangedListener to handle showing/hiding the input warning message
-        binding.userInput.addTextChangedListener(new TextWatcher() {
-            @Override
-            public void afterTextChanged(Editable s) {
-            }
+        binding.userInput.addTextChangedListener(this);
 
-            @Override
-            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
-            }
+        // Build the dialog
+        MaterialAlertDialogBuilder builder = buildMaterialAlertDialog(view);
 
-            /**
-             * When user enters a hidden file name, the 'hidden file' message is shown.
-             * Otherwise, the message is ensured to be hidden.
-             */
-            @Override
-            public void onTextChanged(CharSequence s, int start, int before, int count) {
-                String newFileName = "";
-                if (binding.userInput.getText() != null) {
-                    newFileName = binding.userInput.getText().toString().trim();
-                }
-
-                if (!TextUtils.isEmpty(newFileName) && newFileName.charAt(0) == '.') {
-                    binding.userInputContainer.setError(getText(R.string.hidden_file_name_warning));
-                } else if (TextUtils.isEmpty(newFileName)) {
-                    binding.userInputContainer.setError(getString(R.string.filename_empty));
-                    positiveButton.setEnabled(false);
-                } else if (fileNames.contains(newFileName)) {
-                    binding.userInputContainer.setError(getText(R.string.file_already_exists));
-                    positiveButton.setEnabled(false);
-                } else if (binding.userInputContainer.getError() != null) {
-                    binding.userInputContainer.setError(null);
-                    // Called to remove extra padding
-                    binding.userInputContainer.setErrorEnabled(false);
-                    positiveButton.setEnabled(true);
-                }
-            }
-        });
+        viewThemeUtils.dialog.colorMaterialAlertDialogBackground(binding.userInputContainer.getContext(), builder);
 
-        // Build the dialog
+        return builder.create();
+    }
+
+    private MaterialAlertDialogBuilder buildMaterialAlertDialog(View view) {
         MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity());
-        builder.setView(view)
+
+        builder
+            .setView(view)
             .setPositiveButton(R.string.file_rename, this)
-            .setNeutralButton(R.string.common_cancel, this)
+            .setNegativeButton(R.string.common_cancel, this)
             .setTitle(R.string.rename_dialog_title);
 
-        viewThemeUtils.dialog.colorMaterialAlertDialogBackground(binding.userInputContainer.getContext(), builder);
-
-        return builder.create();
+        return builder;
     }
 
+    private void initAlertDialog() {
+        AlertDialog alertDialog = (AlertDialog) getDialog();
+
+        if (alertDialog != null) {
+            positiveButton = (MaterialButton) alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
+            MaterialButton negativeButton = (MaterialButton) alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE);
+
+            viewThemeUtils.material.colorMaterialButtonPrimaryTonal(positiveButton);
+            viewThemeUtils.material.colorMaterialButtonPrimaryBorderless(negativeButton);
+        }
+    }
 
     @Override
     public void onClick(DialogInterface dialog, int which) {
@@ -219,4 +196,41 @@ public class RenameFileDialogFragment
         super.onDestroyView();
         binding = null;
     }
+
+    @Override
+    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+
+    }
+
+    /**
+     * When user enters a hidden file name, the 'hidden file' message is shown.
+     * Otherwise, the message is ensured to be hidden.
+     */
+    @Override
+    public void onTextChanged(CharSequence s, int start, int before, int count) {
+        String newFileName = "";
+        if (binding.userInput.getText() != null) {
+            newFileName = binding.userInput.getText().toString().trim();
+        }
+
+        if (!TextUtils.isEmpty(newFileName) && newFileName.charAt(0) == '.') {
+            binding.userInputContainer.setError(getText(R.string.hidden_file_name_warning));
+        } else if (TextUtils.isEmpty(newFileName)) {
+            binding.userInputContainer.setError(getString(R.string.filename_empty));
+            positiveButton.setEnabled(false);
+        } else if (fileNames.contains(newFileName)) {
+            binding.userInputContainer.setError(getText(R.string.file_already_exists));
+            positiveButton.setEnabled(false);
+        } else if (binding.userInputContainer.getError() != null) {
+            binding.userInputContainer.setError(null);
+            // Called to remove extra padding
+            binding.userInputContainer.setErrorEnabled(false);
+            positiveButton.setEnabled(true);
+        }
+    }
+
+    @Override
+    public void afterTextChanged(Editable s) {
+
+    }
 }

+ 1 - 1
app/src/main/java/com/owncloud/android/ui/dialog/RenamePublicShareDialogFragment.java

@@ -83,7 +83,7 @@ public class RenamePublicShareDialogFragment
     @Override
     public void onResume() {
         super.onResume();
-        keyboardUtils.showKeyboardForEditText(binding.userInput);
+        keyboardUtils.showKeyboardForEditText(requireDialog().getWindow(), binding.userInput);
     }
 
     @NonNull

+ 1 - 1
app/src/main/java/com/owncloud/android/ui/dialog/SharePasswordDialogFragment.java

@@ -99,7 +99,7 @@ public class SharePasswordDialogFragment extends DialogFragment implements Dialo
     @Override
     public void onResume() {
         super.onResume();
-        keyboardUtils.showKeyboardForEditText(binding.sharePassword);
+        keyboardUtils.showKeyboardForEditText(requireDialog().getWindow(), binding.sharePassword);
     }
 
     /**

+ 10 - 16
app/src/main/java/com/owncloud/android/utils/KeyboardUtils.kt

@@ -1,7 +1,9 @@
 /*
  * Nextcloud Android client application
  *
+ *  @author ZetaTom
  *  @author Álvaro Brey
+ *  Copyright (C) 2023 ZetaTom
  *  Copyright (C) 2022 Álvaro Brey
  *  Copyright (C) 2022 Nextcloud GmbH
  *
@@ -22,26 +24,18 @@
 
 package com.owncloud.android.utils
 
-import android.content.Context
-import android.view.inputmethod.InputMethodManager
+import android.view.Window
 import android.widget.EditText
+import androidx.core.view.WindowCompat
+import androidx.core.view.WindowInsetsCompat
 import javax.inject.Inject
 
 class KeyboardUtils @Inject constructor() {
 
-    fun showKeyboardForEditText(editText: EditText) {
-        editText.requestFocus()
-        // needs 100ms delay to account for focus animations
-        editText.postDelayed({
-            val context = editText.context
-            if (context != null) {
-                val inputMethodManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
-                inputMethodManager.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT)
-            }
-        }, SHOW_INPUT_DELAY_MILLIS)
-    }
-
-    companion object {
-        private const val SHOW_INPUT_DELAY_MILLIS = 100L
+    fun showKeyboardForEditText(window: Window?, editText: EditText) {
+        if (window != null) {
+            editText.requestFocus()
+            WindowCompat.getInsetsController(window, editText).show(WindowInsetsCompat.Type.ime())
+        }
     }
 }

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

@@ -843,6 +843,7 @@
     <string name="trashbin_empty_message">ستتمكن من استعادة الملفات المحذوفة من هنا.</string>
     <string name="trashbin_file_not_deleted">الملف %1$s لا يمكن حذفه!</string>
     <string name="trashbin_file_not_restored">الملف %1$s لا يمكن إسترجاعه!</string>
+    <string name="trashbin_file_remove">حذف نهائي</string>
     <string name="trashbin_loading_failed">فشل تحميل سلة المحذوفات</string>
     <string name="trashbin_not_emptied">تعذر حذف الملفات نهائياً!</string>
     <string name="unlock_file">فتح قفل الملف</string>

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

@@ -836,6 +836,7 @@
     <string name="trashbin_empty_message">You will be able to recover deleted files from here.</string>
     <string name="trashbin_file_not_deleted">File %1$s could not be deleted!</string>
     <string name="trashbin_file_not_restored">File %1$s could not be restored!</string>
+    <string name="trashbin_file_remove">Delete permanently</string>
     <string name="trashbin_loading_failed">Loading trash bin failed!</string>
     <string name="trashbin_not_emptied">Files could not be deleted permanently!</string>
     <string name="unlock_file">Unlock file</string>

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

@@ -807,6 +807,7 @@
     <string name="trashbin_empty_message">Ще можете да възстановите изтритите файлове от тук.</string>
     <string name="trashbin_file_not_deleted">Файлът %1$s не може да бъде изтрит!</string>
     <string name="trashbin_file_not_restored">Файлът %1$s не може да бъде възстановен!</string>
+    <string name="trashbin_file_remove">Изтрий завинаги</string>
     <string name="trashbin_loading_failed">Зареждането на кошчето е неуспешно!</string>
     <string name="trashbin_not_emptied">Файловете не могат да бъдат окончателно изтрити!</string>
     <string name="unlock_file">Отключване на файл</string>

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

@@ -666,6 +666,7 @@
     <string name="trashbin_empty_message">Posupl eo deoc\'h adtapout ar restroù lamet adalek al lec\'h mañ</string>
     <string name="trashbin_file_not_deleted">Ar restr %1$s n\'eo ket evit bezhaãn lamet !</string>
     <string name="trashbin_file_not_restored">Ar restr %1$s n\'eo ket evit bezha adlakaet !</string>
+    <string name="trashbin_file_remove">Lamet da viken</string>
     <string name="trashbin_not_emptied">N\'eo ket posupl lemel ar restr da virviken !</string>
     <string name="unlock_file">Dibrennan ar restr</string>
     <string name="unread_comments">Bez eez eus kemenadennom n\'int ket bet lennet</string>

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

@@ -796,6 +796,7 @@
     <string name="trashbin_empty_message">Des d\'aquí es podran recuperar fitxers suprimits.</string>
     <string name="trashbin_file_not_deleted">El fitxer %1$s no es pot suprimir!</string>
     <string name="trashbin_file_not_restored">El fitxer %1$s no es pot restaurar!</string>
+    <string name="trashbin_file_remove">Suprimeix permanentment</string>
     <string name="trashbin_loading_failed">No s\'ha pogut carregar la paperera!</string>
     <string name="trashbin_not_emptied">Els fitxers no s\'han pogut suprimir permanentment!</string>
     <string name="unlock_file">Desbloca el fitxer</string>

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

@@ -819,6 +819,7 @@ Enheds legitimationsoplysninger er sat op
     <string name="trashbin_empty_message">Du vil kunne gendanne slettede filer herfra.</string>
     <string name="trashbin_file_not_deleted">Fil %1$s kunne ikke slettes!</string>
     <string name="trashbin_file_not_restored">Fil %1$s kunne ikke genskabes!</string>
+    <string name="trashbin_file_remove">Slet permanent</string>
     <string name="trashbin_loading_failed">Indlæsning af papirkurv mislykkedes!</string>
     <string name="trashbin_not_emptied">Filer kunne ikke permanent slettes!</string>
     <string name="unlock_file">Lås op filen</string>

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

@@ -811,6 +811,7 @@
     <string name="trashbin_empty_message">Μπορείτε να ανακτήσετε διαγραμμένα αρχεία από εδώ.</string>
     <string name="trashbin_file_not_deleted">Το αρχείο %1$s δεν μπορεί να διαγραφεί!</string>
     <string name="trashbin_file_not_restored">Το αρχείο %1$s δεν μπορεί να ανακτηθεί!</string>
+    <string name="trashbin_file_remove">Διαγραφή οριστικά</string>
     <string name="trashbin_loading_failed">Αποτυχία φόρτωσης κάδου ανακύκλωσης!</string>
     <string name="trashbin_not_emptied">Τα αρχεία δεν θα διαγραφούν μόνιμα!</string>
     <string name="unlock_file">Ξεκλείδωμα αρχείου</string>