Sfoglia il codice sorgente

Merge branch 'master' into translateError

Álvaro Brey 3 anni fa
parent
commit
2872f8167e
30 ha cambiato i file con 453 aggiunte e 55 eliminazioni
  1. 1 0
      src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java
  2. 10 4
      src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java
  3. 3 0
      src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java
  4. 3 1
      src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java
  5. 18 0
      src/main/java/com/owncloud/android/ui/activity/ShareActivity.java
  6. 58 9
      src/main/java/com/owncloud/android/ui/activity/UploadFilesActivity.java
  7. 3 1
      src/main/java/com/owncloud/android/ui/adapter/TrashbinListAdapter.java
  8. 1 0
      src/main/java/com/owncloud/android/ui/asynctasks/GallerySearchTask.java
  9. 7 0
      src/main/java/com/owncloud/android/ui/dialog/SendShareDialog.java
  10. 4 0
      src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.java
  11. 6 2
      src/main/java/com/owncloud/android/ui/fragment/LocalFileListFragment.java
  12. 37 4
      src/main/java/com/owncloud/android/ui/fragment/UnifiedSearchFragment.kt
  13. 37 0
      src/main/java/com/owncloud/android/ui/fragment/util/PairMediatorLiveData.kt
  14. 1 0
      src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java
  15. 25 11
      src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java
  16. 2 0
      src/main/java/com/owncloud/android/ui/preview/PreviewVideoActivity.java
  17. 7 0
      src/main/java/com/owncloud/android/ui/trashbin/TrashbinActivity.java
  18. 25 10
      src/main/java/com/owncloud/android/utils/BitmapUtils.java
  19. 1 1
      src/main/java/com/owncloud/android/utils/FileSortOrder.java
  20. 9 5
      src/main/res/layout/empty_list.xml
  21. 107 0
      src/main/res/layout/exo_player_control_view.xml
  22. 3 1
      src/main/res/layout/fragment_preview_media.xml
  23. 2 2
      src/main/res/layout/media_control.xml
  24. 3 1
      src/main/res/layout/video_layout.xml
  25. 67 0
      src/main/res/values-hr/strings.xml
  26. 1 0
      src/main/res/values-pt-rBR/strings.xml
  27. 2 2
      src/main/res/values-sl/strings.xml
  28. 1 0
      src/main/res/values-sv/strings.xml
  29. 2 0
      src/main/res/values/strings.xml
  30. 7 1
      src/main/res/values/styles.xml

+ 1 - 0
src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java

@@ -1279,6 +1279,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
 
             mAccount = newAccount;
             mAccountMgr.addAccountExplicitly(mAccount, webViewPassword, null);
+            mAccountMgr.notifyAccountAuthenticated(mAccount);
 
             // add the new account as default in preferences, if there is none already
             User defaultAccount = accountManager.getUser();

+ 10 - 4
src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java

@@ -23,7 +23,6 @@
 
 package com.owncloud.android.datamodel;
 
-import android.accounts.Account;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
@@ -1074,14 +1073,21 @@ public final class ThumbnailsCacheManager {
     }
 
     public static Bitmap addVideoOverlay(Bitmap thumbnail) {
+        int playButtonWidth = (int) (thumbnail.getWidth() * 0.3);
+        int playButtonHeight = (int) (thumbnail.getHeight() * 0.3);
+
         Drawable playButtonDrawable = ResourcesCompat.getDrawable(MainApp.getAppContext().getResources(),
                                                                   R.drawable.view_play,
                                                                   null);
-        Bitmap playButton = BitmapUtils.drawableToBitmap(playButtonDrawable);
+
+        Bitmap playButton = BitmapUtils.drawableToBitmap(playButtonDrawable,
+                                                         playButtonWidth,
+                                                         playButtonHeight);
 
         Bitmap resizedPlayButton = Bitmap.createScaledBitmap(playButton,
-                                                             (int) (thumbnail.getWidth() * 0.3),
-                                                             (int) (thumbnail.getHeight() * 0.3), true);
+                                                             playButtonWidth,
+                                                             playButtonHeight,
+                                                             true);
 
         Bitmap resultBitmap = Bitmap.createBitmap(thumbnail.getWidth(),
                                                   thumbnail.getHeight(),

+ 3 - 0
src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java

@@ -468,6 +468,9 @@ public class RefreshFolderOperation extends RemoteOperation {
         // update eTag
         mLocalFolder.setEtag(remoteFolder.getEtag());
 
+        // update size
+        mLocalFolder.setFileLength(remoteFolder.getFileLength());
+
         DecryptedFolderMetadata metadata = getDecryptedFolderMetadata(encryptedAncestor,
                                                                       mLocalFolder,
                                                                       getClient(),

+ 3 - 1
src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java

@@ -48,7 +48,6 @@ import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewTreeObserver;
 import android.view.WindowManager;
-import android.widget.Toast;
 
 import com.google.android.material.appbar.AppBarLayout;
 import com.google.android.material.snackbar.Snackbar;
@@ -1124,6 +1123,8 @@ public class FileDisplayActivity extends FileActivity
             createMinFragments(null);
         } else {
             // pop back
+            ((CoordinatorLayout.LayoutParams) binding.rootLayout.getLayoutParams())
+                .setBehavior(new AppBarLayout.ScrollingViewBehavior());
             hideSearchView(getCurrentDir());
             showSortListGroup(true);
             super.onBackPressed();
@@ -2187,6 +2188,7 @@ public class FileDisplayActivity extends FileActivity
             Fragment mediaFragment = PreviewMediaFragment.newInstance(file, user.get(), startPlaybackPosition, autoplay);
             setLeftFragment(mediaFragment);
             binding.rightFragmentContainer.setVisibility(View.GONE);
+            ((CoordinatorLayout.LayoutParams) binding.rootLayout.getLayoutParams()).setBehavior(null);
             super.updateActionBarTitleAndHomeButton(file);
         } else {
             Intent previewIntent = new Intent();

+ 18 - 0
src/main/java/com/owncloud/android/ui/activity/ShareActivity.java

@@ -21,6 +21,7 @@
 
 package com.owncloud.android.ui.activity;
 
+import android.app.Activity;
 import android.graphics.Bitmap;
 import android.graphics.PorterDuff;
 import android.os.Bundle;
@@ -34,6 +35,8 @@ import com.owncloud.android.datamodel.ThumbnailsCacheManager;
 import com.owncloud.android.lib.common.operations.RemoteOperation;
 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.operations.GetSharesForFileOperation;
 import com.owncloud.android.ui.fragment.FileDetailSharingFragment;
 import com.owncloud.android.utils.DisplayUtils;
@@ -97,6 +100,21 @@ public class ShareActivity extends FileActivity {
         // Size
         binding.shareFileSize.setText(DisplayUtils.bytesToHumanReadable(file.getFileLength()));
 
+        Activity activity = this;
+        new Thread(() -> {
+            RemoteOperationResult result = new ReadFileRemoteOperation(getFile().getRemotePath())
+                .execute(optionalUser.get().toPlatformAccount(),
+                         activity);
+
+            if (result.isSuccess()) {
+                RemoteFile remoteFile = (RemoteFile) result.getData().get(0);
+                long length = remoteFile.getLength();
+
+                getFile().setFileLength(length);
+                runOnUiThread(() -> binding.shareFileSize.setText(DisplayUtils.bytesToHumanReadable(length)));
+            }
+        }).start();
+
         if (savedInstanceState == null) {
             // Add Share fragment on first creation
             FragmentTransaction ft = getSupportFragmentManager().beginTransaction();

+ 58 - 9
src/main/java/com/owncloud/android/ui/activity/UploadFilesActivity.java

@@ -24,6 +24,7 @@ import android.accounts.Account;
 import android.annotation.SuppressLint;
 import android.app.Activity;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.os.Environment;
 import android.view.Menu;
@@ -36,6 +37,7 @@ import android.widget.Spinner;
 import android.widget.TextView;
 
 import com.google.android.material.button.MaterialButton;
+import com.google.android.material.snackbar.Snackbar;
 import com.nextcloud.client.di.Injectable;
 import com.nextcloud.client.preferences.AppPreferences;
 import com.owncloud.android.R;
@@ -50,10 +52,13 @@ import com.owncloud.android.ui.dialog.LocalStoragePathPickerDialogFragment;
 import com.owncloud.android.ui.dialog.SortingOrderDialogFragment;
 import com.owncloud.android.ui.fragment.ExtendedListFragment;
 import com.owncloud.android.ui.fragment.LocalFileListFragment;
+import com.owncloud.android.utils.DisplayUtils;
 import com.owncloud.android.utils.FileSortOrder;
+import com.owncloud.android.utils.PermissionUtil;
 import com.owncloud.android.utils.theme.ThemeButtonUtils;
 import com.owncloud.android.utils.theme.ThemeColorUtils;
 import com.owncloud.android.utils.theme.ThemeDrawableUtils;
+import com.owncloud.android.utils.theme.ThemeSnackbarUtils;
 import com.owncloud.android.utils.theme.ThemeToolbarUtils;
 import com.owncloud.android.utils.theme.ThemeUtils;
 
@@ -296,12 +301,12 @@ public class UploadFilesActivity extends DrawerActivity implements LocalFileList
                 onBackPressed();
             }
         } else if (itemId == R.id.action_select_all) {
-            item.setChecked(!item.isChecked());
-            mSelectAll = item.isChecked();
+            mSelectAll = !item.isChecked();
+            item.setChecked(mSelectAll);
+            mFileListFragment.selectAllFiles(mSelectAll);
             setSelectAllMenuItem(item, mSelectAll);
-            mFileListFragment.selectAllFiles(item.isChecked());
         } else if (itemId == R.id.action_choose_storage_path) {
-            showLocalStoragePathPickerDialog();
+            checkLocalStoragePathPickerPermission();
         } else {
             retval = super.onOptionsItemSelected(item);
         }
@@ -309,6 +314,29 @@ public class UploadFilesActivity extends DrawerActivity implements LocalFileList
         return retval;
     }
 
+    private void checkLocalStoragePathPickerPermission() {
+        if (!PermissionUtil.checkExternalStoragePermission(this)) {
+            // Check if we should show an explanation
+            if (PermissionUtil.shouldShowRequestPermissionRationale(this,
+                                                                    PermissionUtil.getExternalStoragePermission())) {
+                // Show explanation to the user and then request permission
+                Snackbar snackbar = Snackbar.make(findViewById(android.R.id.content),
+                                                  R.string.permission_storage_access,
+                                                  Snackbar.LENGTH_INDEFINITE)
+                    .setAction(R.string.common_ok, v -> PermissionUtil.requestExternalStoragePermission(this));
+                ThemeSnackbarUtils.colorSnackbar(this, snackbar);
+                snackbar.show();
+            } else {
+                // No explanation needed, request the permission.
+                PermissionUtil.requestExternalStoragePermission(this);
+            }
+
+            return;
+        }
+
+        showLocalStoragePathPickerDialog();
+    }
+
     private void showLocalStoragePathPickerDialog() {
         FragmentManager fm = getSupportFragmentManager();
         FragmentTransaction ft = fm.beginTransaction();
@@ -317,9 +345,26 @@ public class UploadFilesActivity extends DrawerActivity implements LocalFileList
         dialog.show(ft, LocalStoragePathPickerDialogFragment.LOCAL_STORAGE_PATH_PICKER_FRAGMENT);
     }
 
+    @Override
+    public void onRequestPermissionsResult(int requestCode,
+                                           @NonNull String[] permissions,
+                                           @NonNull int[] grantResults) {
+
+        if (requestCode == PermissionUtil.PERMISSIONS_EXTERNAL_STORAGE) {
+            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+                // permission was granted
+                showLocalStoragePathPickerDialog();
+            } else {
+                DisplayUtils.showSnackMessage(this, R.string.permission_storage_access);
+            }
+        } else {
+            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+        }
+    }
+
     @Override
     public void onSortingOrderChosen(FileSortOrder selection) {
-        preferences.setSortOrder(FileSortOrder.Type.uploadFilesView, selection);
+        preferences.setSortOrder(FileSortOrder.Type.localFileListView, selection);
         mFileListFragment.sortFiles(selection);
     }
 
@@ -347,7 +392,7 @@ public class UploadFilesActivity extends DrawerActivity implements LocalFileList
 
             File parentFolder = mCurrentDir.getParentFile();
             if (!parentFolder.canRead()) {
-                showLocalStoragePathPickerDialog();
+                checkLocalStoragePathPickerPermission();
                 return;
             }
 
@@ -410,6 +455,11 @@ public class UploadFilesActivity extends DrawerActivity implements LocalFileList
         return !mDirectories.isEmpty();
     }
 
+    private void updateUploadButtonActive() {
+        final boolean anySelected = mFileListFragment.getCheckedFilesCount() > 0;
+        uploadButton.setEnabled(anySelected);
+    }
+
     private void setSelectAllMenuItem(MenuItem selectAll, boolean checked) {
         selectAll.setChecked(checked);
         if (checked) {
@@ -418,8 +468,7 @@ public class UploadFilesActivity extends DrawerActivity implements LocalFileList
             selectAll.setIcon(
                 ThemeDrawableUtils.tintDrawable(R.drawable.ic_select_all, ThemeColorUtils.primaryColor(this)));
         }
-
-        uploadButton.setEnabled(checked);
+        updateUploadButtonActive();
     }
 
     @Override
@@ -548,7 +597,7 @@ public class UploadFilesActivity extends DrawerActivity implements LocalFileList
     @Override
     public void onFileClick(File file) {
         uploadButton.setEnabled(mFileListFragment.getCheckedFilesCount() > 0);
-        
+
         boolean selectAll = mFileListFragment.getCheckedFilesCount() == mFileListFragment.getFilesCount();
         setSelectAllMenuItem(mOptionsMenu.findItem(R.id.action_select_all), selectAll);
     }

+ 3 - 1
src/main/java/com/owncloud/android/ui/adapter/TrashbinListAdapter.java

@@ -20,6 +20,7 @@
  */
 package com.owncloud.android.ui.adapter;
 
+import android.annotation.SuppressLint;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
@@ -163,12 +164,13 @@ public class TrashbinListAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
         }
     }
 
+    @SuppressLint("NotifyDataSetChanged")
     public void removeFile(TrashbinFile file) {
         int index = files.indexOf(file);
 
         if (index != -1) {
             files.remove(index);
-            notifyItemRemoved(index);
+            notifyDataSetChanged(); // needs to be used to also update footer
         }
     }
 

+ 1 - 0
src/main/java/com/owncloud/android/ui/asynctasks/GallerySearchTask.java

@@ -103,6 +103,7 @@ public class GallerySearchTask extends AsyncTask<Void, Void, RemoteOperationResu
             if (result.isSuccess() && result.getData() != null && !isCancelled()) {
                 if (result.getData() == null || result.getData().size() == 0) {
                     photoFragment.setSearchDidNotFindNewPhotos(true);
+                    photoFragment.setEmptyListMessage(ExtendedListFragment.SearchType.GALLERY_SEARCH);
                 } else {
                     OCFileListAdapter adapter = photoFragment.getAdapter();
 

+ 7 - 0
src/main/java/com/owncloud/android/ui/dialog/SendShareDialog.java

@@ -13,6 +13,7 @@ import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import com.google.android.material.bottomsheet.BottomSheetBehavior;
 import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
 import com.google.android.material.snackbar.Snackbar;
 import com.owncloud.android.R;
@@ -171,6 +172,12 @@ public class SendShareDialog extends BottomSheetDialogFragment {
         return view;
     }
 
+    @Override
+    public void onStart() {
+        super.onStart();
+        BottomSheetBehavior.from((View) requireView().getParent()).setState(BottomSheetBehavior.STATE_EXPANDED);
+    }
+
     private void shareByLink() {
         if (file.isSharedViaLink()) {
             ((FileActivity) getActivity()).getFileOperationsHelper().getFileWithLink(file);

+ 4 - 0
src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.java

@@ -685,6 +685,10 @@ public class ExtendedListFragment extends Fragment implements
                     setMessageForEmptyList(R.string.file_list_empty_shared_headline,
                                            R.string.file_list_empty_shared,
                                            R.drawable.ic_list_empty_shared);
+                } else if (searchType == SearchType.GALLERY_SEARCH) {
+                    setMessageForEmptyList(R.string.file_list_empty_headline_server_search,
+                                           R.string.file_list_empty_gallery,
+                                           R.drawable.file_image);
                 }
             }
         });

+ 6 - 2
src/main/java/com/owncloud/android/ui/fragment/LocalFileListFragment.java

@@ -133,8 +133,12 @@ public class LocalFileListFragment extends ExtendedListFragment implements
 
         listDirectory(mContainerActivity.getInitialDirectory());
 
-        FileSortOrder sortOrder = preferences.getSortOrderByType(FileSortOrder.Type.uploadFilesView);
-        mSortButton.setOnClickListener(v -> openSortingOrderDialogFragment(requireFragmentManager(), sortOrder));
+        mSortButton.setOnClickListener(v -> {
+            FileSortOrder sortOrder = preferences.getSortOrderByType(FileSortOrder.Type.localFileListView);
+            openSortingOrderDialogFragment(requireFragmentManager(), sortOrder);
+        });
+
+        FileSortOrder sortOrder = preferences.getSortOrderByType(FileSortOrder.Type.localFileListView);
         mSortButton.setText(DisplayUtils.getSortOrderStringId(sortOrder));
 
         setGridSwitchButton();

+ 37 - 4
src/main/java/com/owncloud/android/ui/fragment/UnifiedSearchFragment.kt

@@ -20,6 +20,7 @@
  */
 package com.owncloud.android.ui.fragment
 
+import android.content.Intent
 import android.os.Bundle
 import android.view.LayoutInflater
 import android.view.Menu
@@ -29,6 +30,7 @@ import android.view.ViewGroup
 import androidx.annotation.VisibleForTesting
 import androidx.appcompat.widget.SearchView
 import androidx.core.view.MenuItemCompat
+import androidx.core.view.updatePadding
 import androidx.fragment.app.Fragment
 import androidx.lifecycle.ViewModelProvider
 import androidx.recyclerview.widget.GridLayoutManager
@@ -40,20 +42,21 @@ import com.nextcloud.client.network.ClientFactory
 import com.owncloud.android.R
 import com.owncloud.android.databinding.ListFragmentBinding
 import com.owncloud.android.datamodel.FileDataStorageManager
+import com.owncloud.android.datamodel.OCFile
 import com.owncloud.android.lib.common.SearchResultEntry
 import com.owncloud.android.lib.common.utils.Log_OC
 import com.owncloud.android.ui.activity.FileDisplayActivity
 import com.owncloud.android.ui.adapter.UnifiedSearchListAdapter
+import com.owncloud.android.ui.fragment.util.PairMediatorLiveData
 import com.owncloud.android.ui.interfaces.UnifiedSearchListInterface
+import com.owncloud.android.ui.unifiedsearch.IUnifiedSearchViewModel
 import com.owncloud.android.ui.unifiedsearch.ProviderID
 import com.owncloud.android.ui.unifiedsearch.UnifiedSearchSection
 import com.owncloud.android.ui.unifiedsearch.UnifiedSearchViewModel
 import com.owncloud.android.utils.DisplayUtils
+import com.owncloud.android.utils.theme.ThemeColorUtils
+import com.owncloud.android.utils.theme.ThemeDrawableUtils
 import javax.inject.Inject
-import android.content.Intent
-import androidx.core.view.updatePadding
-import com.owncloud.android.datamodel.OCFile
-import com.owncloud.android.ui.unifiedsearch.IUnifiedSearchViewModel
 
 /**
  * Starts query to all capable unified search providers and displays them Opens result in our app, redirect to other
@@ -97,6 +100,36 @@ class UnifiedSearchFragment : Fragment(), Injectable, UnifiedSearchListInterface
         vm.isLoading.observe(this) { loading ->
             binding.swipeContainingList.isRefreshing = loading
         }
+
+        PairMediatorLiveData(vm.searchResults, vm.isLoading).observe(this) { pair ->
+            if (pair.second == false) {
+                var count = 0
+
+                pair.first?.forEach {
+                    count += it.entries.size
+                }
+
+                if (count == 0 && pair.first?.isNotEmpty() == true && context != null) {
+                    binding.emptyList.root.visibility = View.VISIBLE
+                    binding.emptyList.emptyListIcon.visibility = View.VISIBLE
+                    binding.emptyList.emptyListViewHeadline.visibility = View.VISIBLE
+                    binding.emptyList.emptyListViewText.visibility = View.VISIBLE
+                    binding.emptyList.emptyListIcon.visibility = View.VISIBLE
+
+                    binding.emptyList.emptyListViewHeadline.text =
+                        requireContext().getString(R.string.file_list_empty_headline_server_search)
+                    binding.emptyList.emptyListViewText.text =
+                        requireContext().getString(R.string.file_list_empty_unified_search_no_results)
+                    binding.emptyList.emptyListIcon.setImageDrawable(
+                        ThemeDrawableUtils.tintDrawable(
+                            R.drawable.ic_search_grey,
+                            ThemeColorUtils.primaryColor(context, true)
+                        )
+                    )
+                }
+            }
+        }
+
         vm.error.observe(this) { error ->
             if (!error.isNullOrEmpty()) {
                 DisplayUtils.showSnackMessage(binding.root, error)

+ 37 - 0
src/main/java/com/owncloud/android/ui/fragment/util/PairMediatorLiveData.kt

@@ -0,0 +1,37 @@
+/*
+ *
+ * Nextcloud Android client application
+ *
+ * @author Tobias Kaminsky
+ * Copyright (C) 2021 Tobias Kaminsky
+ * Copyright (C) 2021 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/>.
+ * 
+ * Inspired by https://medium.com/codex/how-to-use-mediatorlivedata-with-multiple-livedata-types-a40e1a59e8cf
+ * 
+ */
+
+package com.owncloud.android.ui.fragment.util
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MediatorLiveData
+
+class PairMediatorLiveData<F, S>(firstLiveData: LiveData<F>, secondLiveData: LiveData<S>) :
+    MediatorLiveData<Pair<F?, S?>>() {
+    init {
+        addSource(firstLiveData) { firstLiveDataValue: F -> value = firstLiveDataValue to secondLiveData.value }
+        addSource(secondLiveData) { secondLiveDataValue: S -> value = firstLiveData.value to secondLiveDataValue }
+    }
+}

+ 1 - 0
src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java

@@ -843,6 +843,7 @@ public class FileOperationsHelper {
                 }
 
                 intent.setDataAndType(uri, file.getMimeType());
+                intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                 fileActivity.startActivityForResult(Intent.createChooser(intent,
                                                                          fileActivity.getString(R.string.set_as)),
                                                     200);

+ 25 - 11
src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java

@@ -29,6 +29,7 @@ import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
+import android.graphics.Color;
 import android.media.MediaMetadataRetriever;
 import android.net.Uri;
 import android.os.AsyncTask;
@@ -41,10 +42,11 @@ import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnTouchListener;
 import android.view.ViewGroup;
+import android.widget.ImageView;
 import android.widget.LinearLayout;
 
+import com.google.android.exoplayer2.ExoPlayer;
 import com.google.android.exoplayer2.MediaItem;
-import com.google.android.exoplayer2.SimpleExoPlayer;
 import com.google.android.exoplayer2.ui.StyledPlayerControlView;
 import com.nextcloud.client.account.User;
 import com.nextcloud.client.account.UserAccountManager;
@@ -73,6 +75,7 @@ import javax.inject.Inject;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.StringRes;
+import androidx.appcompat.widget.AppCompatImageButton;
 import androidx.drawerlayout.widget.DrawerLayout;
 
 /**
@@ -94,7 +97,6 @@ public class PreviewMediaFragment extends FileFragment implements OnTouchListene
     private static final String EXTRA_PLAY_POSITION = "PLAY_POSITION";
     private static final String EXTRA_PLAYING = "PLAYING";
     private static final double MIN_DENSITY_RATIO = 24.0;
-    private static final int MENU_FULLSCREEN_ID = 3344;
 
     private static final String FILE = "FILE";
     private static final String USER = "USER";
@@ -113,7 +115,7 @@ public class PreviewMediaFragment extends FileFragment implements OnTouchListene
     @Inject UserAccountManager accountManager;
     FragmentPreviewMediaBinding binding;
     LinearLayout emptyListView;
-    private SimpleExoPlayer exoPlayer;
+    private ExoPlayer exoPlayer;
 
     /**
      * Creates a fragment to preview a file.
@@ -178,6 +180,8 @@ public class PreviewMediaFragment extends FileFragment implements OnTouchListene
 
         emptyListView = binding.emptyView.emptyListView;
 
+        getActivity().findViewById(R.id.sort_list_button_group).setVisibility(View.GONE);
+
         setLoadingView();
         return view;
     }
@@ -297,9 +301,26 @@ public class PreviewMediaFragment extends FileFragment implements OnTouchListene
             // bind to any existing player
             mediaPlayerServiceConnection.bind();
 
-            exoPlayer = new SimpleExoPlayer.Builder(getContext()).build();
+            exoPlayer = new ExoPlayer.Builder(requireContext()).build();
             binding.exoplayerView.setPlayer(exoPlayer);
 
+            LinearLayout linearLayout = binding.exoplayerView.findViewById(R.id.exo_center_controls);
+
+            if (linearLayout.getChildCount() == 5) {
+                AppCompatImageButton fullScreenButton = new AppCompatImageButton(requireContext());
+                fullScreenButton.setImageResource(R.drawable.exo_styled_controls_fullscreen_exit);
+                fullScreenButton.setLayoutParams(new LinearLayout.LayoutParams(143, 143));
+                fullScreenButton.setScaleType(ImageView.ScaleType.FIT_CENTER);
+                fullScreenButton.setBackgroundColor(Color.TRANSPARENT);
+
+                fullScreenButton.setOnClickListener(l -> {
+                    startFullScreenVideo();
+                });
+
+                linearLayout.addView(fullScreenButton);
+                linearLayout.invalidate();
+            }
+
             if (MimeTypeUtil.isAudio(file)) {
                 binding.mediaController.setMediaPlayer(mediaPlayerServiceConnection);
                 binding.mediaController.setVisibility(View.VISIBLE);
@@ -324,10 +345,6 @@ public class PreviewMediaFragment extends FileFragment implements OnTouchListene
     public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
         super.onCreateOptionsMenu(menu, inflater);
         menu.removeItem(R.id.action_search);
-        OCFile file = getFile();
-        if (file != null && MimeTypeUtil.isImageOrVideo(file)) {
-            menu.add(Menu.NONE, MENU_FULLSCREEN_ID, 99, R.string.fullscreen);
-        }
         inflater.inflate(R.menu.item_file, menu);
     }
 
@@ -422,9 +439,6 @@ public class PreviewMediaFragment extends FileFragment implements OnTouchListene
             return true;
         } else if (itemId == R.id.action_stream_media) {
             containerActivity.getFileOperationsHelper().streamMediaFile(getFile());
-        } else if (itemId == MENU_FULLSCREEN_ID) {
-            startFullScreenVideo();
-            return true;
         }
         return super.onOptionsItemSelected(item);
     }

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

@@ -90,6 +90,8 @@ public class PreviewVideoActivity extends FileActivity implements OnCompletionLi
         exoPlayer = new SimpleExoPlayer.Builder(this).build();
         playerView.setPlayer(exoPlayer);
 
+        findViewById(R.id.exo_exit_fs).setOnClickListener(v -> finish());
+
         if (mSavedPlaybackPosition >= 0) {
             exoPlayer.seekTo(mSavedPlaybackPosition);
         }

+ 7 - 0
src/main/java/com/owncloud/android/ui/trashbin/TrashbinActivity.java

@@ -119,6 +119,13 @@ public class TrashbinActivity extends DrawerActivity implements
         setupContent();
     }
 
+    @Override
+    protected void onResume() {
+        super.onResume();
+
+        setDrawerMenuItemChecked(R.id.nav_trashbin);
+    }
+
     private void setupContent() {
         EmptyRecyclerView recyclerView = binding.list;
         recyclerView.setEmptyView(binding.emptyList.emptyListView);

+ 25 - 10
src/main/java/com/owncloud/android/utils/BitmapUtils.java

@@ -372,6 +372,10 @@ public final class BitmapUtils {
     }
 
     public static Bitmap drawableToBitmap(Drawable drawable) {
+        return drawableToBitmap(drawable, -1, -1);
+    }
+
+    public static Bitmap drawableToBitmap(Drawable drawable, int desiredWidth, int desiredHeight) {
         if (drawable instanceof BitmapDrawable) {
             BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
             if (bitmapDrawable.getBitmap() != null) {
@@ -380,20 +384,31 @@ public final class BitmapUtils {
         }
 
         Bitmap bitmap;
-        if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
-            if (drawable.getBounds().width() > 0 && drawable.getBounds().height() > 0) {
-                bitmap = Bitmap.createBitmap(drawable.getBounds().width(),
-                                             drawable.getBounds().height(),
-                                             Bitmap.Config.ARGB_8888);
+        int width;
+        int height;
+
+        if (desiredWidth > 0 && desiredHeight > 0) {
+            width = desiredWidth;
+            height = desiredHeight;
+        } else {
+            if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
+                if (drawable.getBounds().width() > 0 && drawable.getBounds().height() > 0) {
+                    width = drawable.getBounds().width();
+                    height = drawable.getBounds().height();
+                } else {
+                    width = 1;
+                    height = 1;
+                }
             } else {
-                bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
+                width = drawable.getIntrinsicWidth();
+                height = drawable.getIntrinsicHeight();
             }
-        } else {
-            bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
-                                         drawable.getIntrinsicHeight(),
-                                         Bitmap.Config.ARGB_8888);
         }
 
+        bitmap = Bitmap.createBitmap(width,
+                                     height,
+                                     Bitmap.Config.ARGB_8888);
+
         Canvas canvas = new Canvas(bitmap);
         drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
         drawable.draw(canvas);

+ 1 - 1
src/main/java/com/owncloud/android/utils/FileSortOrder.java

@@ -51,7 +51,7 @@ public class FileSortOrder {
     public static final Map<String, FileSortOrder> sortOrders;
 
     public enum Type {
-        trashBinView, localFileListView, uploadFilesView
+        trashBinView, localFileListView
     }
     static {
         HashMap<String, FileSortOrder> temp = new HashMap<>();

+ 9 - 5
src/main/res/layout/empty_list.xml

@@ -19,14 +19,15 @@
 -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/empty_list_view"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:layout_gravity="center"
     android:layout_margin="@dimen/standard_margin"
-    android:gravity="center_vertical|center_horizontal"
+    android:gravity="center_horizontal"
     android:orientation="vertical"
-    android:paddingBottom="@dimen/standard_double_margin">
+    android:paddingTop="@dimen/standard_double_margin">
 
     <ImageView
         android:id="@+id/empty_list_icon"
@@ -34,7 +35,8 @@
         android:layout_height="@dimen/empty_list_icon_layout_height"
         android:contentDescription="@string/file_list_folder"
         android:src="@drawable/ic_list_empty_folder"
-        android:visibility="gone" />
+        android:visibility="gone"
+        tools:visibility="visible" />
 
     <TextView
         android:id="@+id/empty_list_view_headline"
@@ -59,7 +61,8 @@
         android:paddingTop="@dimen/standard_half_padding"
         android:paddingBottom="@dimen/standard_half_padding"
         android:text="@string/file_list_empty"
-        android:visibility="gone" />
+        android:visibility="gone"
+        tools:visibility="visible" />
 
     <com.google.android.material.button.MaterialButton
         android:id="@+id/empty_list_view_action"
@@ -68,5 +71,6 @@
         android:layout_marginTop="@dimen/standard_half_margin"
         android:theme="@style/Button.Primary"
         android:visibility="gone"
-        app:cornerRadius="@dimen/button_corner_radius" />
+        app:cornerRadius="@dimen/button_corner_radius"
+        tools:visibility="visible" />
 </LinearLayout>

+ 107 - 0
src/main/res/layout/exo_player_control_view.xml

@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<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="wrap_content"
+    android:layout_gravity="bottom"
+    android:layoutDirection="ltr"
+    android:background="#CC000000"
+    android:orientation="vertical"
+    tools:targetApi="28">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:paddingTop="4dp"
+        android:orientation="horizontal">
+
+        <ImageButton
+            android:id="@id/exo_prev"
+            style="@style/ExoMediaButton.Previous" />
+
+        <ImageButton
+            android:id="@id/exo_rew"
+            style="@style/ExoMediaButton.Rewind" />
+
+        <ImageButton
+            android:id="@id/exo_shuffle"
+            style="@style/ExoMediaButton" />
+
+        <ImageButton
+            android:id="@id/exo_repeat_toggle"
+            style="@style/ExoMediaButton" />
+
+        <ImageButton
+            android:id="@id/exo_play"
+            style="@style/ExoMediaButton.Play" />
+
+        <ImageButton
+            android:id="@id/exo_pause"
+            style="@style/ExoMediaButton.Pause" />
+
+        <ImageButton
+            android:id="@id/exo_ffwd"
+            style="@style/ExoMediaButton.FastForward" />
+
+        <ImageButton
+            android:id="@id/exo_vr"
+            style="@style/ExoMediaButton.VR" />
+
+        <ImageButton
+            android:id="@+id/exo_exit_fs"
+            style="@style/ExoMediaButton.ExitFullscreen" />
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="4dp"
+        android:gravity="center_vertical"
+        android:orientation="horizontal">
+
+        <TextView
+            android:id="@id/exo_position"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textSize="14sp"
+            android:textStyle="bold"
+            android:paddingLeft="4dp"
+            android:paddingRight="4dp"
+            android:includeFontPadding="false"
+            android:textColor="#FFBEBEBE" />
+
+        <View
+            android:id="@id/exo_progress_placeholder"
+            android:layout_width="0dp"
+            android:layout_weight="1"
+            android:layout_height="26dp" />
+
+        <TextView
+            android:id="@id/exo_duration"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textSize="14sp"
+            android:textStyle="bold"
+            android:paddingLeft="4dp"
+            android:paddingRight="4dp"
+            android:includeFontPadding="false"
+            android:textColor="#FFBEBEBE" />
+
+    </LinearLayout>
+
+</LinearLayout>

+ 3 - 1
src/main/res/layout/fragment_preview_media.xml

@@ -26,6 +26,7 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:gravity="center"
+    android:layout_marginTop="?attr/actionBarSize"
     tools:context=".ui.preview.PreviewMediaFragment">
 
     <ImageView
@@ -43,7 +44,8 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_gravity="center"
-        app:show_buffering="when_playing" />
+        app:show_buffering="when_playing"
+        app:show_next_button="false" />
 
     <com.owncloud.android.media.MediaControlView
         android:id="@+id/media_controller"

+ 2 - 2
src/main/res/layout/media_control.xml

@@ -65,7 +65,7 @@
             android:layout_height="wrap_content"
             android:paddingEnd="@dimen/standard_quarter_padding"
             android:text="@string/placeholder_media_time"
-            android:textColor="@color/text_color_inverse"
+            android:textColor="@color/text_color"
             />
 
         <SeekBar
@@ -87,7 +87,7 @@
             android:layout_height="wrap_content"
             android:paddingStart="@dimen/standard_quarter_padding"
             android:text="@string/placeholder_media_time"
-            android:textColor="@color/text_color_inverse"
+            android:textColor="@color/text_color"
             />
         
     </LinearLayout>

+ 3 - 1
src/main/res/layout/video_layout.xml

@@ -19,8 +19,10 @@
   along with this program. If not, see <https://www.gnu.org/licenses/>.
 -->
 <com.google.android.exoplayer2.ui.StyledPlayerView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:id="@+id/videoPlayer"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:layout_gravity="center"
-    android:background="@color/black" />
+    android:background="@color/black"
+    app:controller_layout_id="@layout/exo_player_control_view" />

+ 67 - 0
src/main/res/values-hr/strings.xml

@@ -14,6 +14,7 @@
     <string name="action_send_share">Pošalji/podijeli</string>
     <string name="action_switch_grid_view">Prikaz rešetke</string>
     <string name="action_switch_list_view">Prikaz popisa</string>
+    <string name="actionbar_calendar_contacts_restore">Vrati kontakte i kalendar</string>
     <string name="actionbar_copy">Kopiraj</string>
     <string name="actionbar_mkdir">Nova mapa</string>
     <string name="actionbar_move">Premjesti</string>
@@ -32,6 +33,7 @@
     <string name="add_another_public_share_link">Dodaj drugu poveznicu</string>
     <string name="add_new_public_share">Dodaj novu poveznicu za javno dijeljenje</string>
     <string name="add_to_cloud">Dodaj na %1$s</string>
+    <string name="advanced_settings">Napredne postavke</string>
     <string name="allow_resharing">Dopusti ponovno dijeljenje</string>
     <string name="appbar_search_in">Traži u %s</string>
     <string name="associated_account_not_found">Pripadajući račun nije pronađen!</string>
@@ -74,11 +76,15 @@
     <string name="autoupload_hide_folder">Sakrij mapu</string>
     <string name="avatar">Avatar</string>
     <string name="away">Odsutan</string>
+    <string name="backup_settings">Postavke sigurnosne kopije</string>
+    <string name="backup_title">Sigurnosno kopiranje kontakata i kalendara</string>
     <string name="battery_optimization_close">Zatvori</string>
     <string name="battery_optimization_disable">Onemogući</string>
     <string name="battery_optimization_message">Možda je omogućena optimizacija rada baterije na uređaju. Mogućnost automatskog otpremanja AutoUpload djeluje samo ako izuzmete ovu aplikaciju iz optimizacije baterije.</string>
     <string name="battery_optimization_title">Optimizacija baterije</string>
     <string name="brute_force_delay">Odgođeno zbog previše pogrešnih pokušaja</string>
+    <string name="calendar">Kalendar</string>
+    <string name="calendars">Kalendari</string>
     <string name="certificate_load_problem">Došlo je do poteškoća prilikom učitavanja vjerodajnice.</string>
     <string name="changelog_dev_version">Zapis promjena razvojne inačice</string>
     <string name="checkbox">Potvrdni okvir</string>
@@ -97,11 +103,13 @@
     <string name="common_cancel">Odustani</string>
     <string name="common_cancel_sync">Prekini sinkronizaciju</string>
     <string name="common_choose_account">Odaberite račun</string>
+    <string name="common_confirm">Potvrdi</string>
     <string name="common_delete">Izbriši</string>
     <string name="common_error">Pogreška</string>
     <string name="common_error_out_memory">Nema dovoljno memorije</string>
     <string name="common_error_unknown">Nepoznata pogreška</string>
     <string name="common_loading">Učitavanje…</string>
+    <string name="common_next">Dalje</string>
     <string name="common_no">Ne</string>
     <string name="common_ok">U redu</string>
     <string name="common_pending">Na čekanju</string>
@@ -146,6 +154,7 @@
     <string name="conflict_new_file">Nova datoteka</string>
     <string name="contactlist_item_icon">Ikona korisnika za popis kontakata</string>
     <string name="contactlist_no_permission">Nema dopuštenja, ništa nije uvezeno.</string>
+    <string name="contacts">Kontakti</string>
     <string name="contacts_backup_button">Sigurnosno kopiraj</string>
     <string name="contacts_preferences_backup_scheduled">Sigurnosno kopiranje je zakazano i počet će uskoro</string>
     <string name="contacts_preferences_import_scheduled">Uvoz je zakazan i počet će uskoro</string>
@@ -172,16 +181,21 @@
     <string name="create_rich_workspace">Dodaj informacije o mapi</string>
     <string name="creates_rich_workspace">stvara informacije o mapi</string>
     <string name="credentials_disabled">Vjerodajnice onemogućene</string>
+    <string name="daily_backup">Svakodnevno sigurnosno kopiranje</string>
+    <string name="data_to_back_up">Podaci za sigurnosno kopiranje</string>
     <string name="date_unknown">Nepoznato</string>
     <string name="default_credentials_wrong">Netočne vjerodajnice</string>
     <string name="delete_account">Izbriši račun</string>
     <string name="delete_account_warning">Želite li ukloniti račun %s i izbrisati sve lokalne datoteke?\n\nBrisanje se ne može poništiti.</string>
     <string name="delete_entries">Izbriši unose</string>
+    <string name="delete_link">Izbriši poveznicu</string>
     <string name="deselect_all">Odznači sve</string>
+    <string name="destination_filename">Naziv odredišne datoteke</string>
     <string name="dev_version_new_version_available">Dostupna je nova inačica</string>
     <string name="dev_version_no_information_available">Nema dostupnih informacija.</string>
     <string name="dev_version_no_new_version_available">Nema nove inačice.</string>
     <string name="dialog_close">Zatvori</string>
+    <string name="did_not_check_for_dupes">Provjera postojanja duplikata nije izvršena.</string>
     <string name="digest_algorithm_not_available">Algoritam sažetka nije dostupan na vašem uređaju.</string>
     <string name="direct_login_failed">Prijava putem izravne poveznice nije uspjela!</string>
     <string name="disable_new_media_folder_detection_notifications">Onemogući</string>
@@ -236,9 +250,11 @@
     <string name="end_to_end_encryption_title">Postavi šifriranje</string>
     <string name="end_to_end_encryption_unsuccessful">Spremanje ključeva nije uspjelo, pokušajte ponovno.</string>
     <string name="end_to_end_encryption_wrong_password">Došlo je do pogreške tijekom dešifriranja. Pogrešna zaporka?</string>
+    <string name="enter_destination_filename">Unesite naziv odredišne datoteke</string>
     <string name="enter_filename">Unesite naziv datoteke</string>
     <string name="error__upload__local_file_not_copied">%1$s se ne može kopirati u lokalnu mapu na uređaju %2$s</string>
     <string name="error_cant_bind_to_operations_service">Kritična pogreška: nije moguće izvršiti radnje</string>
+    <string name="error_choosing_date">Pogreška pri odabiru datuma</string>
     <string name="error_comment_file">Pogreška pri komentiranju datoteke</string>
     <string name="error_crash_title">Ispad %1$s</string>
     <string name="error_report_issue_action">Prijavi</string>
@@ -368,11 +384,16 @@
     <string name="invalid_url">Neispravan URL</string>
     <string name="invisible">Nevidljiva</string>
     <string name="label_empty">Oznaka ne može biti prazna</string>
+    <string name="last_backup">Zadnja sigurnosna kopija: %1$s</string>
     <string name="link">Poveznica</string>
+    <string name="link_name">Naziv pozivnice</string>
     <string name="link_share_allow_upload_and_editing">Omogući otpremanje i uređivanje</string>
+    <string name="link_share_editing">Uređivanje</string>
     <string name="link_share_file_drop">Povlačenje datoteke (samo za otpremanje)</string>
     <string name="link_share_read_only">Samo za čitanje</string>
+    <string name="link_share_view_only">Samo za gledanje</string>
     <string name="list_layout">Navedeni izgled</string>
+    <string name="load_more_results">Učitaj više rezultata</string>
     <string name="local_file_list_empty">Nema datoteka u ovoj mapi.</string>
     <string name="local_file_not_found_message">Datoteka nije pronađena u lokalnom datotečnom sustavu</string>
     <string name="local_folder_friendly_path">%1$s/%2$s</string>
@@ -410,6 +431,7 @@
     <string name="menu_item_sort_by_name_z_a">Z – A</string>
     <string name="menu_item_sort_by_size_biggest_first">Najveći prvi</string>
     <string name="menu_item_sort_by_size_smallest_first">Najmanji prvi</string>
+    <string name="more">Više</string>
     <string name="move_file_error">Došlo je do pogreške prilikom premještanja ove datoteke ili mape</string>
     <string name="move_file_invalid_into_descendent">Nije moguće premjestiti mapu u jednu od svojih osnovnih mapa</string>
     <string name="move_file_invalid_overwrite">Datoteka je već prisutna u odredišnoj mapi</string>
@@ -425,14 +447,19 @@
     <string name="new_media_folder_videos">videozapis</string>
     <string name="new_notification">Nova obavijest</string>
     <string name="new_version_was_created">Stvorena je nova inačica</string>
+    <string name="no_actions">Nema radnji za ovog korisnika</string>
     <string name="no_browser_available">Nema dostupnih aplikacija za upravljanje poveznicama</string>
+    <string name="no_calendar_exists">Ne postoji kalendar</string>
+    <string name="no_email_app_available">Nema dostupnih aplikacija za upravljanje adresama e-pošte</string>
     <string name="no_mutliple_accounts_allowed">Dopušten je samo jedan račun</string>
     <string name="no_pdf_app_available">Nema dostupnih aplikacija za upravljanje PDF datotekama</string>
+    <string name="no_share_permission_selected">Odaberite barem jedno dopuštenje za dijeljenje.</string>
     <string name="note_confirm">Pošalji</string>
     <string name="note_could_not_sent">Nije moguće poslati bilješku</string>
     <string name="note_icon_hint">Ikona bilješke</string>
     <string name="notification_action_failed">Izvršavanje radnje nije uspjelo.</string>
     <string name="notification_channel_download_description">Prikazuje napredak preuzimanja</string>
+    <string name="notification_channel_download_name_short">Preuzimanja</string>
     <string name="notification_channel_file_sync_description">Prikazuje napredak i rezultate sinkronizacije datoteka</string>
     <string name="notification_channel_file_sync_name">Sinkronizacija datoteka</string>
     <string name="notification_channel_general_description">Prikazuje obavijesti o novim medijskim mapama i slično</string>
@@ -442,6 +469,7 @@
     <string name="notification_channel_push_description">Prikazuje push obavijesti koje šalje poslužitelj: navode u komentarima, primanje novih udaljenih dijeljenja, obavijesti administratora itd.</string>
     <string name="notification_channel_push_name">Push obavijesti</string>
     <string name="notification_channel_upload_description">Prikazuje napredak otpreme</string>
+    <string name="notification_channel_upload_name_short">Otpreme</string>
     <string name="notification_icon">Ikona obavijesti</string>
     <string name="notifications_no_results_headline">Nema obavijesti</string>
     <string name="notifications_no_results_message">Provjerite kasnije.</string>
@@ -492,6 +520,7 @@
     <string name="prefs_category_dev">Dev</string>
     <string name="prefs_category_general">Općenito</string>
     <string name="prefs_category_more">Više</string>
+    <string name="prefs_daily_backup_summary">Svakodnevno sigurnosno kopiranje vašeg kalendara i kontakata</string>
     <string name="prefs_e2e_mnemonic">E2E mnemonička oznaka</string>
     <string name="prefs_e2e_no_device_credentials">Omogućite vjerodajnice uređaja kako biste prikazali mnemoničku oznaku.</string>
     <string name="prefs_enable_media_scan_notifications">Prikaži obavijesti o skeniranju medija</string>
@@ -549,7 +578,9 @@
     <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>
     <string name="restore">Vrati datoteku</string>
+    <string name="restore_backup">Vrati sigurnosnu kopiju</string>
     <string name="restore_button_description">Vrati izbrisanu datoteku</string>
+    <string name="restore_selected">Vrati odabrano</string>
     <string name="retrieving_file">Dohvaćanje datoteke...</string>
     <string name="richdocuments_failed_to_load_document">Učitavanje dokumenta nije uspjelo!</string>
     <string name="scanQR_description">Prijavite se putem QR koda</string>
@@ -565,18 +596,23 @@
     <string name="screenshot_05_autoUpload_subline">fotografija i videozapisa</string>
     <string name="screenshot_06_davdroid_heading">Kalendar i kontakti</string>
     <string name="screenshot_06_davdroid_subline">Sinkronizacija s DAVx5</string>
+    <string name="search_error">Pogreška pri dohvaćanju rezultata pretraživanja</string>
     <string name="select_all">Odaberi sve</string>
     <string name="select_one_template">Odaberite jedan predložak</string>
     <string name="select_template">Odaberi predložak</string>
     <string name="send">Pošalji</string>
     <string name="send_note">Pošalji bilješku primatelju</string>
+    <string name="send_share">Pošalji dijeljenje</string>
     <string name="sendbutton_description">Ikona gumba za slanje</string>
     <string name="set_as">Postavi kao</string>
+    <string name="set_note">Postavi bilješku</string>
     <string name="set_picture_as">Koristi sliku kao</string>
     <string name="set_status">Postavi status</string>
     <string name="set_status_message">Postavi poruku statusa</string>
     <string name="share">Dijeli</string>
+    <string name="share_copy_link">Dijeli i kopiraj poveznicu</string>
     <string name="share_dialog_title">Dijeljenje</string>
+    <string name="share_expiration_date_format">%1$s</string>
     <string name="share_expiration_date_label">Istječe %1$s</string>
     <string name="share_file">Dijeli %1$s</string>
     <string name="share_group_clarification">%1$s (grupa)</string>
@@ -585,6 +621,7 @@
     <string name="share_internal_link_to_folder_text">Poveznicu za interno dijeljenje mogu rabiti samo korisnici koji smiju pristupiti ovoj mapi</string>
     <string name="share_known_remote_on_clarification">na %1$s</string>
     <string name="share_link">Dijeli poveznicu</string>
+    <string name="share_link_empty_note_message">Unesite bilješku.</string>
     <string name="share_link_empty_password">Morate unijeti zaporku</string>
     <string name="share_link_file_error">Došlo je do pogreške prilikom dijeljenja ove datoteke ili mape.</string>
     <string name="share_link_file_no_exist">Dijeljenje nije moguće. Provjerite postoji li datoteka.</string>
@@ -594,11 +631,18 @@
     <string name="share_link_with_label">Dijeli poveznicu (%1$s)</string>
     <string name="share_no_expiration_date_label">Postavi datum isteka</string>
     <string name="share_no_password_title">Postavi zaporku</string>
+    <string name="share_open_in">Otvori u…</string>
     <string name="share_password_title">Zaštićeno zaporkom</string>
+    <string name="share_permission_can_edit">Uređivanje moguće</string>
+    <string name="share_permission_file_drop">Povlačenje datoteke</string>
+    <string name="share_permission_view_only">Samo za gledanje</string>
+    <string name="share_permissions">Dopuštenja za dijeljenje</string>
     <string name="share_remote_clarification">%1$s (udaljeno)</string>
     <string name="share_room_clarification">%1$s (razgovor)</string>
     <string name="share_search">Naziv, ID udruženog oblaka ili adresa e-pošte…</string>
+    <string name="share_send_new_email">Pošalji novu poruku e-pošte</string>
     <string name="share_send_note">Obavijest primatelju</string>
+    <string name="share_settings">Postavke</string>
     <string name="share_via_link_hide_download">Sakrij preuzimanje</string>
     <string name="share_via_link_section_title">Dijeli poveznicu</string>
     <string name="share_via_link_send_link_label">Pošalji poveznicu</string>
@@ -664,6 +708,7 @@
     <string name="strict_mode">Ograničeni način rada: nije dopuštena HTTP veza!</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="suggest">Predloži</string>
     <string name="sync_conflicts_in_favourites_ticker">Postoje nepodudaranja</string>
     <string name="sync_current_folder_was_removed">Mapa %1$s više ne postoji</string>
     <string name="sync_fail_content">Nije moguće sinkronizirati %1$s</string>
@@ -808,6 +853,8 @@
     <string name="what_s_new_image">Što je nova slika</string>
     <string name="whats_new_skip">Preskoči</string>
     <string name="whats_new_title">Novo u %1$s</string>
+    <string name="whats_your_status">Koji je vaš status?</string>
+    <string name="write_email">Pošalji poruku e-pošte</string>
     <string name="wrong_storage_path">Put pohrane ne postoji!</string>
     <string name="wrong_storage_path_desc">To može biti zbog vraćanja sigurnosne kopije na drugom uređaju. Provjerite postavke i prilagodite put pohrane.</string>
     <plurals name="sync_fail_in_favourites_content">
@@ -820,6 +867,26 @@
         <item quantity="few">Nije uspjelo kopiranje datoteka %1$d iz mape %2$s u</item>
         <item quantity="other">Nije uspjelo kopiranje datoteka %1$d iz mape %2$s u</item>
     </plurals>
+    <plurals name="wrote_n_events_to">
+        <item quantity="one">Zapisan %1$d događaj u %2$s</item>
+        <item quantity="few">Zapisano %1$d događaja u %2$s</item>
+        <item quantity="other">Zapisano %1$d događaja u %2$s</item>
+    </plurals>
+    <plurals name="created_n_uids_to">
+        <item quantity="one">Stvoren %1$d novi UID</item>
+        <item quantity="few">Stvorena %1$d nova UID-a</item>
+        <item quantity="other">Stvoreno %1$d novih UID-a</item>
+    </plurals>
+    <plurals name="processed_n_entries">
+        <item quantity="one">Obrađen %d unos.</item>
+        <item quantity="few">Obrađena %d unosa.</item>
+        <item quantity="other">Obrađeno %d unosa.</item>
+    </plurals>
+    <plurals name="found_n_duplicates">
+        <item quantity="one">Pronađen %d dupli unos.</item>
+        <item quantity="few">Pronađena %d dupla unosa.</item>
+        <item quantity="other">Pronađeno %d duplih unosa.</item>
+    </plurals>
     <plurals name="file_list__footer__folder">
         <item quantity="one">Mapa %1$d</item>
         <item quantity="few">Mape %1$d</item>

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

@@ -374,6 +374,7 @@
     <string name="forward">Adiante</string>
     <string name="fourHours">4 horas</string>
     <string name="fullscreen">Tela cheia</string>
+    <string name="hidden_file_name_warning">O nome resultará em um arquivo oculto</string>
     <string name="hint_name">Nome</string>
     <string name="hint_note">Anotação</string>
     <string name="hint_password">Senha</string>

+ 2 - 2
src/main/res/values-sl/strings.xml

@@ -635,7 +635,7 @@
     <string name="share_send_note">Sporočilo za prejemnika</string>
     <string name="share_settings">Nastavitve</string>
     <string name="share_via_link_hide_download">Skrij prejem</string>
-    <string name="share_via_link_section_title">Omogoči souporabo prek povezave</string>
+    <string name="share_via_link_section_title">Omogoči souporabo s povezavo</string>
     <string name="share_via_link_send_link_label">Pošlji povezavo</string>
     <string name="share_via_link_unset_password">Odstrani izbor</string>
     <string name="share_with_title">Omogoči souporabo …</string>
@@ -749,7 +749,7 @@
     <string name="unshare_link_file_no_exist">Ni mogoče prekiniti souporabe. Preverite, ali datoteka obstaja.</string>
     <string name="unshare_link_forbidden_permissions">za preklic souporabe datoteke.</string>
     <string name="unsharing_failed">Odstranjevanje souporabe je spodletelo</string>
-    <string name="untrusted_domain">Zaznan je dostop prek domene, ki ni zaupanja vredna. Več podrobnosti je zapisanih v dokumentaciji.</string>
+    <string name="untrusted_domain">Zaznan je dostop z domene, ki ni zaupanja vredna. Več podrobnosti je zapisanih v dokumentaciji.</string>
     <string name="update_link_file_error">Prišlo je do napake med posodabljanjem mesta souporabe</string>
     <string name="update_link_file_no_exist">Posodobitev ni mogoča. Preverite, ali datoteka obstaja.</string>
     <string name="update_link_forbidden_permissions">za posodobitev mesta souporabe</string>

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

@@ -374,6 +374,7 @@
     <string name="forward">Vidarebefordra</string>
     <string name="fourHours">4 timmar</string>
     <string name="fullscreen">Fullskärm</string>
+    <string name="hidden_file_name_warning">Namngivning kommer att resultera i en dold fil</string>
     <string name="hint_name">Namn</string>
     <string name="hint_note">Anteckning</string>
     <string name="hint_password">Lösenord</string>

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

@@ -1005,5 +1005,7 @@
     <string name="load_more_results">Load more results</string>
     <string name="file_management_permission">Permissions needed</string>
     <string name="file_management_permission_text">%1$s needs file management permissions to work properly. Please enable it in the following screen to continue.</string>
+    <string name="file_list_empty_unified_search_no_results">No results found for your query</string>
+    <string name="file_list_empty_gallery">Found no images or videos</string>
     <string name="error_creating_file_from_template">Error creating file from template</string>
 </resources>

+ 7 - 1
src/main/res/values/styles.xml

@@ -428,4 +428,10 @@
         <item name="android:typeface">sans</item>
         <item name="android:textStyle">bold</item>
     </style>
-</resources>
+
+    <style name="ExoMediaButton.ExitFullscreen" parent="ExoStyledControls.Button.Center">
+        <item name="android:src">@drawable/exo_styled_controls_fullscreen_exit</item>
+        <item name="android:contentDescription">@string/exo_controls_fullscreen_exit_description</item>
+        <item name="android:padding">@dimen/exo_icon_padding</item>
+    </style>
+</resources>