Bläddra i källkod

Merge pull request #12278 from nextcloud/feature/new_grid-layout

New Grid Layout
Alper Öztürk 1 år sedan
förälder
incheckning
251ef247c1

+ 46 - 0
app/src/main/java/com/nextcloud/utils/extensions/ViewExtensions.kt

@@ -0,0 +1,46 @@
+/*
+ * Nextcloud Android client application
+ *
+ * @author Alper Ozturk
+ * Copyright (C) 2023 Alper Ozturk
+ * Copyright (C) 2023 Nextcloud GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package com.nextcloud.utils.extensions
+
+import android.content.Context
+import android.graphics.Outline
+import android.util.TypedValue
+import android.view.View
+import android.view.ViewOutlineProvider
+
+fun createRoundedOutline(context: Context, cornerRadiusValue: Float): ViewOutlineProvider {
+    return object : ViewOutlineProvider() {
+        override fun getOutline(view: View, outline: Outline) {
+            val left = 0
+            val top = 0
+            val right = view.width
+            val bottom = view.height
+            val cornerRadius = TypedValue.applyDimension(
+                TypedValue.COMPLEX_UNIT_DIP,
+                cornerRadiusValue,
+                context.resources.displayMetrics
+            ).toInt()
+
+            outline.setRoundRect(left, top, right, bottom, cornerRadius.toFloat())
+        }
+    }
+}

+ 0 - 1
app/src/main/java/com/owncloud/android/MainApp.java

@@ -129,7 +129,6 @@ import static com.owncloud.android.ui.activity.ContactsPreferenceActivity.PREFER
  * Contains methods to build the "static" strings. These strings were before constants in different classes
  * Contains methods to build the "static" strings. These strings were before constants in different classes
  */
  */
 public class MainApp extends MultiDexApplication implements HasAndroidInjector {
 public class MainApp extends MultiDexApplication implements HasAndroidInjector {
-
     public static final OwnCloudVersion OUTDATED_SERVER_VERSION = NextcloudVersion.nextcloud_23;
     public static final OwnCloudVersion OUTDATED_SERVER_VERSION = NextcloudVersion.nextcloud_23;
     public static final OwnCloudVersion MINIMUM_SUPPORTED_SERVER_VERSION = OwnCloudVersion.nextcloud_16;
     public static final OwnCloudVersion MINIMUM_SUPPORTED_SERVER_VERSION = OwnCloudVersion.nextcloud_16;
 
 

+ 6 - 2
app/src/main/java/com/owncloud/android/ui/adapter/ListGridImageViewHolder.kt

@@ -22,7 +22,9 @@
 package com.owncloud.android.ui.adapter
 package com.owncloud.android.ui.adapter
 
 
 import android.view.View
 import android.view.View
+import android.widget.ImageButton
 import android.widget.ImageView
 import android.widget.ImageView
+import android.widget.LinearLayout
 import android.widget.TextView
 import android.widget.TextView
 import com.elyeproj.loaderviewlibrary.LoaderImageView
 import com.elyeproj.loaderviewlibrary.LoaderImageView
 
 
@@ -32,12 +34,14 @@ interface ListGridImageViewHolder {
     val shimmerThumbnail: LoaderImageView
     val shimmerThumbnail: LoaderImageView
     val favorite: ImageView
     val favorite: ImageView
     val localFileIndicator: ImageView
     val localFileIndicator: ImageView
+    val imageFileName: TextView?
     val shared: ImageView
     val shared: ImageView
     val checkbox: ImageView
     val checkbox: ImageView
     val itemLayout: View
     val itemLayout: View
     val unreadComments: ImageView
     val unreadComments: ImageView
-
-    val gridLivePhotoIndicator: TextView?
+    val more: ImageButton?
+    val fileFeaturesLayout: LinearLayout?
+    val gridLivePhotoIndicator: ImageView?
     val livePhotoIndicator: TextView?
     val livePhotoIndicator: TextView?
     val livePhotoIndicatorSeparator: TextView?
     val livePhotoIndicatorSeparator: TextView?
 }
 }

+ 4 - 3
app/src/main/java/com/owncloud/android/ui/adapter/LocalFileListAdapter.java

@@ -32,6 +32,7 @@ import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 import android.widget.TextView;
 
 
+import com.nextcloud.android.common.ui.theme.utils.ColorRole;
 import com.nextcloud.client.preferences.AppPreferences;
 import com.nextcloud.client.preferences.AppPreferences;
 import com.owncloud.android.R;
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.ThumbnailsCacheManager;
 import com.owncloud.android.datamodel.ThumbnailsCacheManager;
@@ -54,6 +55,7 @@ import java.util.concurrent.Executors;
 
 
 import androidx.annotation.NonNull;
 import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
 import androidx.annotation.VisibleForTesting;
+import androidx.core.content.ContextCompat;
 import androidx.recyclerview.widget.RecyclerView;
 import androidx.recyclerview.widget.RecyclerView;
 
 
 /**
 /**
@@ -186,11 +188,10 @@ public class LocalFileListAdapter extends RecyclerView.Adapter<RecyclerView.View
                 } else {
                 } else {
                     gridViewHolder.checkbox.setVisibility(View.VISIBLE);
                     gridViewHolder.checkbox.setVisibility(View.VISIBLE);
                     if (isCheckedFile(file)) {
                     if (isCheckedFile(file)) {
-                        gridViewHolder.itemLayout.setBackgroundColor(mContext.getResources()
-                                                                         .getColor(R.color.selected_item_background));
+                        gridViewHolder.itemLayout.setBackgroundColor(ContextCompat.getColor(mContext, R.color.selected_item_background));
 
 
                         gridViewHolder.checkbox.setImageDrawable(
                         gridViewHolder.checkbox.setImageDrawable(
-                            viewThemeUtils.platform.tintPrimaryDrawable(mContext, R.drawable.ic_checkbox_marked));
+                            viewThemeUtils.platform.tintDrawable(mContext, R.drawable.ic_checkbox_marked, ColorRole.PRIMARY));
                     } else {
                     } else {
                         gridViewHolder.itemLayout.setBackgroundColor(mContext.getResources().getColor(R.color.bg_default));
                         gridViewHolder.itemLayout.setBackgroundColor(mContext.getResources().getColor(R.color.bg_default));
                         gridViewHolder.checkbox.setImageResource(R.drawable.ic_checkbox_blank_outline);
                         gridViewHolder.checkbox.setImageResource(R.drawable.ic_checkbox_blank_outline);

+ 46 - 10
app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java

@@ -39,7 +39,9 @@ import android.text.TextUtils;
 import android.view.LayoutInflater;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewGroup;
+import android.widget.ImageButton;
 import android.widget.ImageView;
 import android.widget.ImageView;
+import android.widget.LinearLayout;
 
 
 import com.elyeproj.loaderviewlibrary.LoaderImageView;
 import com.elyeproj.loaderviewlibrary.LoaderImageView;
 import com.nextcloud.android.common.ui.theme.utils.ColorRole;
 import com.nextcloud.android.common.ui.theme.utils.ColorRole;
@@ -300,6 +302,7 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
                 return headerId;
                 return headerId;
             }
             }
 
 
+
             // skip header
             // skip header
             position--;
             position--;
         }
         }
@@ -365,8 +368,7 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
     @Override
     @Override
     public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
     public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
         switch (viewType) {
         switch (viewType) {
-            default:
-            case VIEWTYPE_ITEM:
+            default -> {
                 if (gridView) {
                 if (gridView) {
                     return new OCFileListGridItemViewHolder(
                     return new OCFileListGridItemViewHolder(
                         GridItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)
                         GridItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)
@@ -376,8 +378,8 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
                         ListItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)
                         ListItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)
                     );
                     );
                 }
                 }
-
-            case VIEWTYPE_IMAGE:
+            }
+            case VIEWTYPE_IMAGE -> {
                 if (gridView) {
                 if (gridView) {
                     return new OCFileListGridImageViewHolder(
                     return new OCFileListGridImageViewHolder(
                         GridImageBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)
                         GridImageBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)
@@ -387,23 +389,22 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
                         ListItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)
                         ListItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)
                     );
                     );
                 }
                 }
-
-            case VIEWTYPE_FOOTER:
+            }
+            case VIEWTYPE_FOOTER -> {
                 return new OCFileListFooterViewHolder(
                 return new OCFileListFooterViewHolder(
                     ListFooterBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)
                     ListFooterBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)
                 );
                 );
-
-            case VIEWTYPE_HEADER:
+            }
+            case VIEWTYPE_HEADER -> {
                 ListHeaderBinding binding = ListHeaderBinding.inflate(
                 ListHeaderBinding binding = ListHeaderBinding.inflate(
                     LayoutInflater.from(parent.getContext()),
                     LayoutInflater.from(parent.getContext()),
                     parent,
                     parent,
                     false);
                     false);
-
                 ViewGroup.LayoutParams layoutParams = binding.headerView.getLayoutParams();
                 ViewGroup.LayoutParams layoutParams = binding.headerView.getLayoutParams();
                 layoutParams.height = (int) (parent.getHeight() * 0.3);
                 layoutParams.height = (int) (parent.getHeight() * 0.3);
                 binding.headerView.setLayoutParams(layoutParams);
                 binding.headerView.setLayoutParams(layoutParams);
-
                 return new OCFileListHeaderViewHolder(binding);
                 return new OCFileListHeaderViewHolder(binding);
+            }
         }
         }
     }
     }
 
 
@@ -430,6 +431,8 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
             }
             }
 
 
             ocFileListDelegate.bindGridViewHolder(gridViewHolder, file, searchType);
             ocFileListDelegate.bindGridViewHolder(gridViewHolder, file, searchType);
+            checkVisibilityOfMoreButtons(gridViewHolder);
+            checkVisibilityOfFileFeaturesLayout(gridViewHolder);
 
 
             if (holder instanceof ListItemViewHolder) {
             if (holder instanceof ListItemViewHolder) {
                 bindListItemViewHolder((ListItemViewHolder) gridViewHolder, file);
                 bindListItemViewHolder((ListItemViewHolder) gridViewHolder, file);
@@ -437,12 +440,45 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
 
 
             if (holder instanceof ListGridItemViewHolder) {
             if (holder instanceof ListGridItemViewHolder) {
                 bindListGridItemViewHolder((ListGridItemViewHolder) holder, file);
                 bindListGridItemViewHolder((ListGridItemViewHolder) holder, file);
+                checkVisibilityOfMoreButtons((ListGridItemViewHolder) holder);
+                checkVisibilityOfFileFeaturesLayout((ListGridItemViewHolder) holder);
             }
             }
 
 
             updateLivePhotoIndicators(gridViewHolder, file);
             updateLivePhotoIndicators(gridViewHolder, file);
         }
         }
     }
     }
 
 
+    private void checkVisibilityOfFileFeaturesLayout(ListGridImageViewHolder holder) {
+        int fileFeaturesVisibility = View.GONE;
+        LinearLayout fileFeaturesLayout = holder.getFileFeaturesLayout();
+
+        if (fileFeaturesLayout == null) {
+            return;
+        }
+
+        for (int i = 0; i < fileFeaturesLayout.getChildCount(); i++) {
+            View child = fileFeaturesLayout.getChildAt(i);
+            if (child.getVisibility() == View.VISIBLE) {
+                fileFeaturesVisibility = View.VISIBLE;
+            }
+        }
+
+        fileFeaturesLayout.setVisibility(fileFeaturesVisibility);
+    }
+
+    private void checkVisibilityOfMoreButtons(ListGridImageViewHolder holder) {
+        ImageButton moreButton = holder.getMore();
+        if (moreButton == null) {
+            return;
+        }
+
+        if (isMultiSelect()) {
+            moreButton.setVisibility(View.GONE);
+        } else {
+            moreButton.setVisibility(View.VISIBLE);
+        }
+    }
+
     private void mergeOCFilesForLivePhoto() {
     private void mergeOCFilesForLivePhoto() {
         List<OCFile> filesToRemove = new ArrayList<>();
         List<OCFile> filesToRemove = new ArrayList<>();
 
 

+ 64 - 27
app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt

@@ -27,10 +27,13 @@ import android.graphics.drawable.ColorDrawable
 import android.os.AsyncTask
 import android.os.AsyncTask
 import android.view.View
 import android.view.View
 import android.widget.ImageView
 import android.widget.ImageView
+import androidx.core.content.ContextCompat
 import androidx.core.content.res.ResourcesCompat
 import androidx.core.content.res.ResourcesCompat
 import com.elyeproj.loaderviewlibrary.LoaderImageView
 import com.elyeproj.loaderviewlibrary.LoaderImageView
+import com.nextcloud.android.common.ui.theme.utils.ColorRole
 import com.nextcloud.client.account.User
 import com.nextcloud.client.account.User
 import com.nextcloud.client.preferences.AppPreferences
 import com.nextcloud.client.preferences.AppPreferences
+import com.nextcloud.utils.extensions.createRoundedOutline
 import com.owncloud.android.R
 import com.owncloud.android.R
 import com.owncloud.android.datamodel.FileDataStorageManager
 import com.owncloud.android.datamodel.FileDataStorageManager
 import com.owncloud.android.datamodel.OCFile
 import com.owncloud.android.datamodel.OCFile
@@ -142,7 +145,7 @@ class OCFileListDelegate(
                     storageManager,
                     storageManager,
                     asyncGalleryTasks,
                     asyncGalleryTasks,
                     file.remoteId,
                     file.remoteId,
-                    context.resources.getColor(R.color.bg_default)
+                    ContextCompat.getColor(context, R.color.bg_default)
                 )
                 )
                 var drawable = MimeTypeUtil.getFileTypeIcon(
                 var drawable = MimeTypeUtil.getFileTypeIcon(
                     file.mimeType,
                     file.mimeType,
@@ -204,6 +207,7 @@ class OCFileListDelegate(
         searchType: SearchType?
         searchType: SearchType?
     ) {
     ) {
         // thumbnail
         // thumbnail
+        gridViewHolder.imageFileName?.text = file.fileName
         gridViewHolder.thumbnail.tag = file.fileId
         gridViewHolder.thumbnail.tag = file.fileId
         DisplayUtils.setThumbnail(
         DisplayUtils.setThumbnail(
             file,
             file,
@@ -218,6 +222,7 @@ class OCFileListDelegate(
             viewThemeUtils,
             viewThemeUtils,
             syncFolderProvider
             syncFolderProvider
         )
         )
+
         // item layout + click listeners
         // item layout + click listeners
         bindGridItemLayout(file, gridViewHolder)
         bindGridItemLayout(file, gridViewHolder)
 
 
@@ -232,17 +237,20 @@ class OCFileListDelegate(
         }
         }
 
 
         // download state
         // download state
-        gridViewHolder.localFileIndicator.visibility = View.INVISIBLE // default first
+        gridViewHolder.localFileIndicator.visibility = View.GONE // default first
 
 
         // metadata (downloaded, favorite)
         // metadata (downloaded, favorite)
         bindGridMetadataViews(file, gridViewHolder)
         bindGridMetadataViews(file, gridViewHolder)
 
 
         // shares
         // shares
-        val shouldHideShare = gridView ||
+        val shouldHideShare = (
             hideItemOptions ||
             hideItemOptions ||
-            !file.isFolder && file.isEncrypted ||
-            file.isEncrypted && !EncryptionUtils.supportsSecureFiledrop(file, user) ||
-            searchType == SearchType.FAVORITE_SEARCH
+                !file.isFolder &&
+                file.isEncrypted ||
+                file.isEncrypted &&
+                !EncryptionUtils.supportsSecureFiledrop(file, user) ||
+                searchType == SearchType.FAVORITE_SEARCH
+            )
         if (shouldHideShare) {
         if (shouldHideShare) {
             gridViewHolder.shared.visibility = View.GONE
             gridViewHolder.shared.visibility = View.GONE
         } else {
         } else {
@@ -263,34 +271,63 @@ class OCFileListDelegate(
     }
     }
 
 
     private fun bindGridItemLayout(file: OCFile, gridViewHolder: ListGridImageViewHolder) {
     private fun bindGridItemLayout(file: OCFile, gridViewHolder: ListGridImageViewHolder) {
-        if (highlightedItem != null && file.fileId == highlightedItem!!.fileId) {
-            gridViewHolder.itemLayout.setBackgroundColor(
-                context.resources
-                    .getColor(R.color.selected_item_background)
-            )
-        } else if (isCheckedFile(file)) {
-            gridViewHolder.itemLayout.setBackgroundColor(
-                context.resources
-                    .getColor(R.color.selected_item_background)
-            )
-            gridViewHolder.checkbox.setImageDrawable(
-                viewThemeUtils.platform.tintPrimaryDrawable(context, R.drawable.ic_checkbox_marked)
-            )
-        } else {
-            gridViewHolder.itemLayout.setBackgroundColor(context.resources.getColor(R.color.bg_default))
-            gridViewHolder.checkbox.setImageResource(R.drawable.ic_checkbox_blank_outline)
+        setItemLayoutBackgroundColor(file, gridViewHolder)
+        setCheckBoxImage(file, gridViewHolder)
+        setItemLayoutOnClickListeners(file, gridViewHolder)
+
+        gridViewHolder.more?.setOnClickListener {
+            ocFileListFragmentInterface.onOverflowIconClicked(file, it)
         }
         }
+    }
+
+    private fun setItemLayoutOnClickListeners(file: OCFile, gridViewHolder: ListGridImageViewHolder) {
         gridViewHolder.itemLayout.setOnClickListener { ocFileListFragmentInterface.onItemClicked(file) }
         gridViewHolder.itemLayout.setOnClickListener { ocFileListFragmentInterface.onItemClicked(file) }
+
         if (!hideItemOptions) {
         if (!hideItemOptions) {
-            gridViewHolder.itemLayout.isLongClickable = true
-            gridViewHolder.itemLayout.setOnLongClickListener {
-                ocFileListFragmentInterface.onLongItemClicked(
-                    file
-                )
+            gridViewHolder.itemLayout.apply {
+                isLongClickable = true
+                setOnLongClickListener {
+                    ocFileListFragmentInterface.onLongItemClicked(
+                        file
+                    )
+                }
             }
             }
         }
         }
     }
     }
 
 
+    private fun setItemLayoutBackgroundColor(file: OCFile, gridViewHolder: ListGridImageViewHolder) {
+        val cornerRadius = context.resources.getDimension(R.dimen.selected_grid_container_radius)
+
+        val isDarkModeActive = (syncFolderProvider?.preferences?.isDarkModeEnabled == true)
+        val selectedItemBackgroundColorId: Int = if (isDarkModeActive) {
+            R.color.action_mode_background
+        } else {
+            R.color.selected_item_background
+        }
+
+        val itemLayoutBackgroundColorId: Int = if (file.fileId == highlightedItem?.fileId || isCheckedFile(file)) {
+            selectedItemBackgroundColorId
+        } else {
+            R.color.bg_default
+        }
+
+        gridViewHolder.itemLayout.apply {
+            outlineProvider = createRoundedOutline(context, cornerRadius)
+            clipToOutline = true
+            setBackgroundColor(ContextCompat.getColor(context, itemLayoutBackgroundColorId))
+        }
+    }
+
+    private fun setCheckBoxImage(file: OCFile, gridViewHolder: ListGridImageViewHolder) {
+        if (isCheckedFile(file)) {
+            gridViewHolder.checkbox.setImageDrawable(
+                viewThemeUtils.platform.tintDrawable(context, R.drawable.ic_checkbox_marked, ColorRole.PRIMARY)
+            )
+        } else {
+            gridViewHolder.checkbox.setImageResource(R.drawable.ic_checkbox_blank_outline)
+        }
+    }
+
     private fun bindGridMetadataViews(file: OCFile, gridViewHolder: ListGridImageViewHolder) {
     private fun bindGridMetadataViews(file: OCFile, gridViewHolder: ListGridImageViewHolder) {
         if (showMetadata) {
         if (showMetadata) {
             showLocalFileIndicator(file, gridViewHolder)
             showLocalFileIndicator(file, gridViewHolder)

+ 11 - 2
app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridImageViewHolder.kt

@@ -22,7 +22,9 @@
 package com.owncloud.android.ui.adapter
 package com.owncloud.android.ui.adapter
 
 
 import android.view.View
 import android.view.View
+import android.widget.ImageButton
 import android.widget.ImageView
 import android.widget.ImageView
+import android.widget.LinearLayout
 import android.widget.TextView
 import android.widget.TextView
 import androidx.recyclerview.widget.RecyclerView
 import androidx.recyclerview.widget.RecyclerView
 import com.elyeproj.loaderviewlibrary.LoaderImageView
 import com.elyeproj.loaderviewlibrary.LoaderImageView
@@ -33,9 +35,13 @@ internal class OCFileListGridImageViewHolder(var binding: GridImageBinding) :
         binding.root
         binding.root
     ),
     ),
     ListGridImageViewHolder {
     ListGridImageViewHolder {
+
     override val thumbnail: ImageView
     override val thumbnail: ImageView
         get() = binding.thumbnail
         get() = binding.thumbnail
 
 
+    override val imageFileName: TextView
+        get() = binding.Filename
+
     override fun showVideoOverlay() {
     override fun showVideoOverlay() {
         // noop
         // noop
     }
     }
@@ -54,8 +60,11 @@ internal class OCFileListGridImageViewHolder(var binding: GridImageBinding) :
         get() = binding.ListItemLayout
         get() = binding.ListItemLayout
     override val unreadComments: ImageView
     override val unreadComments: ImageView
         get() = binding.unreadComments
         get() = binding.unreadComments
-
-    override val gridLivePhotoIndicator: TextView
+    override val more: ImageButton
+        get() = binding.more
+    override val fileFeaturesLayout: LinearLayout
+        get() = binding.fileFeaturesLayout
+    override val gridLivePhotoIndicator: ImageView
         get() = binding.gridLivePhotoIndicator
         get() = binding.gridLivePhotoIndicator
     override val livePhotoIndicator: TextView?
     override val livePhotoIndicator: TextView?
         get() = null
         get() = null

+ 9 - 1
app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridItemViewHolder.kt

@@ -22,7 +22,9 @@
 package com.owncloud.android.ui.adapter
 package com.owncloud.android.ui.adapter
 
 
 import android.view.View
 import android.view.View
+import android.widget.ImageButton
 import android.widget.ImageView
 import android.widget.ImageView
+import android.widget.LinearLayout
 import android.widget.TextView
 import android.widget.TextView
 import androidx.recyclerview.widget.RecyclerView
 import androidx.recyclerview.widget.RecyclerView
 import com.elyeproj.loaderviewlibrary.LoaderImageView
 import com.elyeproj.loaderviewlibrary.LoaderImageView
@@ -48,6 +50,8 @@ internal class OCFileListGridItemViewHolder(var binding: GridItemBinding) :
         get() = binding.favoriteAction
         get() = binding.favoriteAction
     override val localFileIndicator: ImageView
     override val localFileIndicator: ImageView
         get() = binding.localFileIndicator
         get() = binding.localFileIndicator
+    override val imageFileName: TextView?
+        get() = null
     override val shared: ImageView
     override val shared: ImageView
         get() = binding.sharedIcon
         get() = binding.sharedIcon
     override val checkbox: ImageView
     override val checkbox: ImageView
@@ -57,12 +61,16 @@ internal class OCFileListGridItemViewHolder(var binding: GridItemBinding) :
     override val unreadComments: ImageView
     override val unreadComments: ImageView
         get() = binding.unreadComments
         get() = binding.unreadComments
 
 
-    override val gridLivePhotoIndicator: TextView?
+    override val gridLivePhotoIndicator: ImageView?
         get() = null
         get() = null
     override val livePhotoIndicator: TextView?
     override val livePhotoIndicator: TextView?
         get() = null
         get() = null
     override val livePhotoIndicatorSeparator: TextView?
     override val livePhotoIndicatorSeparator: TextView?
         get() = null
         get() = null
+    override val fileFeaturesLayout: LinearLayout
+        get() = binding.fileFeaturesLayout
+    override val more: ImageButton
+        get() = binding.more
 
 
     init {
     init {
         binding.favoriteAction.drawable.mutate()
         binding.favoriteAction.drawable.mutate()

+ 8 - 1
app/src/main/java/com/owncloud/android/ui/adapter/OCFileListItemViewHolder.kt

@@ -22,6 +22,7 @@
 package com.owncloud.android.ui.adapter
 package com.owncloud.android.ui.adapter
 
 
 import android.view.View
 import android.view.View
+import android.widget.ImageButton
 import android.widget.ImageView
 import android.widget.ImageView
 import android.widget.LinearLayout
 import android.widget.LinearLayout
 import android.widget.TextView
 import android.widget.TextView
@@ -37,7 +38,7 @@ internal class OCFileListItemViewHolder(private var binding: ListItemBinding) :
         binding.root
         binding.root
     ),
     ),
     ListItemViewHolder {
     ListItemViewHolder {
-    override val gridLivePhotoIndicator: TextView?
+    override val gridLivePhotoIndicator: ImageView?
         get() = null
         get() = null
     override val livePhotoIndicator: TextView
     override val livePhotoIndicator: TextView
         get() = binding.livePhotoIndicator
         get() = binding.livePhotoIndicator
@@ -73,12 +74,18 @@ internal class OCFileListItemViewHolder(private var binding: ListItemBinding) :
         binding.thumbnailLayout.videoOverlay.visibility = View.VISIBLE
         binding.thumbnailLayout.videoOverlay.visibility = View.VISIBLE
     }
     }
 
 
+    override val more: ImageButton?
+        get() = null
+    override val fileFeaturesLayout: LinearLayout?
+        get() = null
     override val shimmerThumbnail: LoaderImageView
     override val shimmerThumbnail: LoaderImageView
         get() = binding.thumbnailLayout.thumbnailShimmer
         get() = binding.thumbnailLayout.thumbnailShimmer
     override val favorite: ImageView
     override val favorite: ImageView
         get() = binding.favoriteAction
         get() = binding.favoriteAction
     override val localFileIndicator: ImageView
     override val localFileIndicator: ImageView
         get() = binding.localFileIndicator
         get() = binding.localFileIndicator
+    override val imageFileName: TextView?
+        get() = null
     override val shared: ImageView
     override val shared: ImageView
         get() = binding.sharedIcon
         get() = binding.sharedIcon
     override val checkbox: ImageView
     override val checkbox: ImageView

+ 2 - 2
app/src/main/java/com/owncloud/android/utils/DisplayUtils.java

@@ -977,9 +977,9 @@ public final class DisplayUtils {
     }
     }
 
 
     private static void configShimmerGridImageSize(LoaderImageView thumbnailShimmer, float gridColumns) {
     private static void configShimmerGridImageSize(LoaderImageView thumbnailShimmer, float gridColumns) {
-        FrameLayout.LayoutParams targetLayoutParams = (FrameLayout.LayoutParams) thumbnailShimmer.getLayoutParams();
-
         try {
         try {
+            FrameLayout.LayoutParams targetLayoutParams = (FrameLayout.LayoutParams) thumbnailShimmer.getLayoutParams();
+
             final Point screenSize = getScreenSize(thumbnailShimmer.getContext());
             final Point screenSize = getScreenSize(thumbnailShimmer.getContext());
             final int marginLeftAndRight = targetLayoutParams.leftMargin + targetLayoutParams.rightMargin;
             final int marginLeftAndRight = targetLayoutParams.leftMargin + targetLayoutParams.rightMargin;
             final int size = Math.round(screenSize.x / gridColumns - marginLeftAndRight);
             final int size = Math.round(screenSize.x / gridColumns - marginLeftAndRight);

+ 166 - 119
app/src/main/res/layout/grid_image.xml

@@ -15,129 +15,176 @@
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 
 -->
 -->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
+<LinearLayout
     xmlns:tools="http://schemas.android.com/tools"
     xmlns:tools="http://schemas.android.com/tools"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:id="@+id/ListItemLayout"
     android:id="@+id/ListItemLayout"
+    android:orientation="vertical"
+    android:layout_marginEnd="@dimen/grid_container_margin"
+    android:layout_marginTop="@dimen/grid_container_margin"
+    android:gravity="center"
     android:layout_width="match_parent"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:layout_gravity="center_horizontal"
-    android:foreground="?android:attr/selectableItemBackground"
-    android:gravity="center_horizontal"
-    android:orientation="vertical">
-
-    <com.elyeproj.loaderviewlibrary.LoaderImageView
-        android:id="@+id/thumbnail_shimmer"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_margin="@dimen/grid_image_icon_margin"
-        android:contentDescription="@null"
-        android:visibility="gone"
-        app:corners="6"
-        app:height_weight="0.6"
-        app:width_weight="0.4" />
-
-    <com.owncloud.android.ui.SquareImageView
-        android:id="@+id/thumbnail"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:contentDescription="@null"
-        android:padding="@dimen/grid_image_icon_padding"
-        android:scaleType="centerCrop"
-        android:src="@drawable/file_image" />
-
-    <ImageView
-        tools:visibility="visible"
-        android:id="@+id/favorite_action"
-        android:layout_width="16dp"
-        android:layout_height="16dp"
-        android:layout_gravity="top|end"
-        android:layout_margin="@dimen/standard_quarter_margin"
-        android:contentDescription="@string/favorite_icon"
-        android:visibility="gone"
-        android:src="@drawable/favorite" />
-
-    <ImageView
-        tools:visibility="visible"
-        android:id="@+id/unreadComments"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="top|end"
-        android:layout_marginTop="70dp"
-        android:layout_marginEnd="@dimen/standard_quarter_margin"
-        android:clickable="true"
-        android:contentDescription="@string/unread_comments"
-        android:focusable="true"
-        android:src="@drawable/ic_comment_grid"
-        android:visibility="gone" />
-
-    <ImageView
-        tools:visibility="visible"
-        android:id="@+id/localFileIndicator"
-        android:layout_width="16dp"
-        android:layout_height="16dp"
-        android:layout_gravity="bottom|end"
-        android:layout_marginTop="@dimen/standard_quarter_margin"
-        android:layout_marginEnd="@dimen/standard_quarter_margin"
-        android:layout_marginBottom="@dimen/standard_quarter_margin"
-        android:contentDescription="@string/synced_icon"
-        android:src="@drawable/ic_synced" />
-
-    <FrameLayout
-        android:layout_width="28dp"
-        android:layout_height="28dp"
-        android:layout_gravity="top|end"
-        android:layout_marginTop="32dp"
-        android:layout_marginEnd="@dimen/standard_quarter_margin"
-        android:background="@drawable/rounded_rect"
-        android:backgroundTint="#F6F6F6">
+    android:layout_height="@dimen/grid_container_height">
 
 
-        <ImageView
-            android:id="@+id/sharedIcon"
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:layout_width="@dimen/grid_container_width"
+        android:layout_height="@dimen/grid_container_height">
+
+        <com.elyeproj.loaderviewlibrary.LoaderImageView
+            android:id="@+id/thumbnail_shimmer"
+            android:visibility="gone"
+            android:layout_marginBottom="@dimen/grid_thumbnail_margin_bottom"
+            android:layout_width="@dimen/standard_list_item_size"
+            android:layout_height="@dimen/standard_list_item_size"
+            android:contentDescription="@null"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent"
+            tools:visibility="visible" />
+
+        <com.owncloud.android.ui.SquareImageView
+            android:id="@+id/thumbnail"
+            android:layout_marginBottom="@dimen/grid_thumbnail_margin_bottom"
+            android:layout_width="@dimen/standard_list_item_size"
+            android:layout_height="@dimen/standard_list_item_size"
+            android:contentDescription="@null"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent"
+            android:scaleType="centerCrop"
             tools:visibility="visible"
             tools:visibility="visible"
-            android:layout_gravity="center"
+            android:src="@drawable/file_image" />
+
+        <LinearLayout
+            android:id="@+id/file_features_layout"
             android:layout_width="wrap_content"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_height="wrap_content"
-            android:contentDescription="@string/shared_icon_shared_via_link"
-            android:src="@drawable/shared_via_link" />
-
-    </FrameLayout>
-
-    <TextView
-        android:id="@+id/grid_live_photo_indicator"
-        tools:visibility="visible"
-        android:visibility="gone"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        app:drawableTint="@color/list_item_lastmod_and_filesize_text"
-        android:background="@drawable/rounded_rect"
-        android:backgroundTint="#F6F6F6"
-        android:paddingVertical="10dp"
-        android:paddingHorizontal="2dp"
-        android:layout_marginLeft="@dimen/standard_quarter_margin"
-        android:layout_marginRight="@dimen/standard_quarter_margin"
-        android:text="@string/file_list_live"
-        android:drawablePadding="@dimen/standard_eight_padding"
-        android:gravity="center"
-        android:layout_gravity="start|bottom"
-        android:textColor="@color/list_item_lastmod_and_filesize_text"
-        android:textSize="@dimen/two_line_secondary_text_size"
-        app:drawableTopCompat="@drawable/ic_live_photo" />
-
-    <TextView
-        android:id="@+id/live_photo_indicator_separator"
-        android:visibility="gone"
-        android:layout_width="0dp"
-        android:layout_height="0dp"/>
-
-    <ImageView
-        tools:visibility="visible"
-        android:id="@+id/custom_checkbox"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center_vertical|top"
-        android:layout_marginLeft="@dimen/standard_quarter_margin"
-        android:layout_marginRight="@dimen/standard_quarter_margin"
-        android:contentDescription="@string/checkbox"
-        android:src="@android:drawable/checkbox_off_background" />
-</FrameLayout>
+            android:gravity="center"
+            android:layout_marginEnd="@dimen/grid_layout_file_features_margin_end"
+            android:layout_marginBottom="@dimen/grid_layout_margin_bottom"
+            android:alpha="0.9"
+            android:background="@drawable/rounded_rect"
+            android:backgroundTint="@color/grid_file_features_background_color"
+            android:orientation="horizontal"
+            android:padding="@dimen/standard_quarter_padding"
+            android:translationZ="4dp"
+            app:layout_constraintBottom_toBottomOf="@+id/thumbnail"
+            app:layout_constraintEnd_toEndOf="parent">
+
+            <ImageView
+                android:id="@+id/favorite_action"
+                android:layout_width="@dimen/grid_layout_item_size"
+                android:layout_height="@dimen/grid_layout_item_size"
+                android:layout_marginEnd="@dimen/grid_layout_margin_end"
+                android:contentDescription="@string/favorite_icon"
+                android:src="@drawable/favorite" />
+
+            <ImageView
+                android:id="@+id/videoOverlay"
+                android:layout_width="@dimen/grid_layout_item_size"
+                android:layout_height="@dimen/grid_layout_item_size"
+                android:layout_marginEnd="@dimen/grid_layout_margin_end"
+                android:contentDescription="@string/video_overlay_icon"
+                android:src="@drawable/video_white"
+                android:visibility="gone"
+                app:tint="@color/grid_file_features_icon_color"
+                tools:visibility="visible" />
+
+            <ImageView
+                android:id="@+id/sharedIcon"
+                android:layout_width="@dimen/grid_layout_item_size"
+                android:layout_height="@dimen/grid_layout_item_size"
+                android:layout_marginEnd="@dimen/grid_layout_margin_end"
+                android:contentDescription="@string/shared_icon_shared_via_link"
+                android:src="@drawable/shared_via_link"
+                app:tint="@color/grid_file_features_icon_color"
+                tools:visibility="visible" />
+
+            <ImageView
+                android:id="@+id/unreadComments"
+                tools:ignore="TouchTargetSizeCheck"
+                android:layout_width="@dimen/grid_layout_item_size"
+                android:layout_height="@dimen/grid_layout_item_size"
+                android:layout_marginEnd="@dimen/grid_layout_margin_end"
+                android:clickable="true"
+                android:contentDescription="@string/unread_comments"
+                android:focusable="true"
+                android:src="@drawable/ic_comment_grid"
+                android:visibility="gone"
+                app:tint="@color/grid_file_features_icon_color"
+                tools:visibility="visible" />
+
+            <ImageView
+                android:id="@+id/grid_live_photo_indicator"
+                tools:ignore="TouchTargetSizeCheck"
+                android:layout_width="@dimen/grid_layout_item_size"
+                android:layout_height="@dimen/grid_layout_item_size"
+                android:layout_marginEnd="@dimen/grid_layout_margin_end"
+                android:clickable="true"
+                android:contentDescription="@string/grid_file_features_live_photo_content_description"
+                android:focusable="true"
+                android:src="@drawable/ic_live_photo"
+                android:visibility="gone"
+                app:tint="@color/grid_file_features_icon_color"
+                tools:visibility="visible" />
+
+            <ImageView
+                android:id="@+id/localFileIndicator"
+                android:layout_width="@dimen/grid_layout_item_size"
+                android:layout_height="@dimen/grid_layout_item_size"
+                android:layout_marginEnd="@dimen/grid_layout_margin_end"
+                android:contentDescription="@string/synced_icon"
+                android:src="@drawable/ic_synced"
+                tools:visibility="visible" />
+
+        </LinearLayout>
+
+        <ImageView
+            android:id="@+id/custom_checkbox"
+            android:layout_width="@dimen/grid_checkbox_size"
+            android:layout_height="@dimen/grid_checkbox_size"
+            android:layout_marginStart="@dimen/grid_checkbox_margin"
+            android:layout_marginTop="@dimen/grid_checkbox_margin"
+            android:contentDescription="@string/checkbox"
+            android:src="@android:drawable/checkbox_off_background"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent"
+            tools:visibility="visible" />
+
+        <TextView
+            android:id="@+id/Filename"
+            android:layout_width="@dimen/grid_filename_width"
+            android:layout_height="@dimen/grid_bottom_view_height"
+            android:layout_gravity="center"
+            android:layout_marginBottom="@dimen/grid_bottom_view_margin_bottom"
+            android:ellipsize="middle"
+            android:gravity="center"
+            android:singleLine="true"
+            android:text="@string/placeholder_filename"
+            android:textColor="@color/text_color"
+            android:textSize="@dimen/grid_item_text_size"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            tools:visibility="visible" />
+
+        <ImageButton
+            android:id="@+id/more"
+            android:layout_width="@dimen/grid_bottom_view_height"
+            android:layout_marginBottom="@dimen/grid_bottom_view_margin_bottom"
+            tools:ignore="TouchTargetSizeCheck"
+            android:layout_height="@dimen/grid_bottom_view_height"
+            android:layout_marginEnd="@dimen/grid_bottom_view_margin_end"
+            android:layout_gravity="center"
+            android:background="@color/transparent"
+            android:contentDescription="@string/overflow_menu"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:srcCompat="@drawable/ic_dots_vertical" />
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+
+</LinearLayout>

+ 133 - 99
app/src/main/res/layout/grid_item.xml

@@ -15,130 +15,164 @@
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 
 -->
 -->
-<com.owncloud.android.ui.SquareLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
+<LinearLayout
     xmlns:tools="http://schemas.android.com/tools"
     xmlns:tools="http://schemas.android.com/tools"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:id="@+id/ListItemLayout"
     android:id="@+id/ListItemLayout"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:layout_gravity="center_horizontal"
+    android:layout_marginEnd="@dimen/grid_container_margin"
+    android:layout_marginTop="@dimen/grid_container_margin"
+    android:orientation="vertical"
     android:gravity="center"
     android:gravity="center"
-    android:orientation="vertical">
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/grid_container_height">
 
 
     <androidx.constraintlayout.widget.ConstraintLayout
     <androidx.constraintlayout.widget.ConstraintLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content">
+        android:layout_width="@dimen/grid_container_width"
+        android:layout_height="@dimen/grid_container_height">
+
+        <com.elyeproj.loaderviewlibrary.LoaderImageView
+            android:id="@+id/thumbnail_shimmer"
+            android:visibility="gone"
+            android:layout_marginBottom="@dimen/grid_thumbnail_margin_bottom"
+            android:layout_width="@dimen/standard_list_item_size"
+            android:layout_height="@dimen/standard_list_item_size"
+            android:contentDescription="@null"
+            android:src="@drawable/folder"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent"
+            tools:visibility="visible" />
 
 
         <ImageView
         <ImageView
-            android:id="@+id/favorite_action"
+            android:id="@+id/thumbnail"
+            android:layout_width="@dimen/standard_list_item_size"
+            android:layout_height="@dimen/standard_list_item_size"
+            android:layout_marginBottom="@dimen/grid_thumbnail_margin_bottom"
+            android:contentDescription="@null"
+            android:src="@drawable/folder"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent"
+            tools:visibility="visible" />
+
+        <LinearLayout
+            android:id="@+id/file_features_layout"
             android:layout_width="wrap_content"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_gravity="top|end"
-            android:layout_margin="@dimen/standard_quarter_margin"
-            android:src="@drawable/favorite"
-            android:contentDescription="@string/favorite_icon"
-            app:layout_constraintEnd_toEndOf="@+id/frameLayout"
-            app:layout_constraintTop_toTopOf="@id/frameLayout"
-            app:layout_constraintBottom_toTopOf="@id/frameLayout"/>
-
-        <FrameLayout
-            android:id="@+id/frameLayout"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center_horizontal"
-            app:layout_constraintBottom_toBottomOf="parent">
-
-            <com.elyeproj.loaderviewlibrary.LoaderImageView
-                android:id="@+id/thumbnail_shimmer"
-                android:layout_width="@dimen/standard_list_item_size"
-                android:layout_height="@dimen/standard_list_item_size"
-                android:layout_gravity="center"
-                android:visibility="gone"
-                app:corners="8" />
-
-            <FrameLayout
-                android:layout_width="@dimen/standard_list_item_size"
-                android:layout_height="@dimen/standard_list_item_size"
-                android:layout_gravity="center">
-
-                <ImageView
-                    android:id="@+id/thumbnail"
-                    android:layout_width="@dimen/standard_list_item_size"
-                    android:layout_height="@dimen/standard_list_item_size"
-                    android:contentDescription="@null"
-                    android:src="@drawable/folder" />
-
-                <ImageView
-                    android:id="@+id/videoOverlay"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_marginStart="4dp"
-                    android:layout_marginTop="4dp"
-                    android:contentDescription="@string/video_overlay_icon"
-                    android:src="@drawable/video_white"
-                    android:visibility="gone"
-                    tools:visibility="visible" />
-            </FrameLayout>
+            android:gravity="center"
+            android:layout_marginEnd="@dimen/grid_layout_file_features_margin_end"
+            android:layout_marginBottom="@dimen/grid_layout_margin_bottom"
+            android:alpha="0.9"
+            android:background="@drawable/rounded_rect"
+            android:backgroundTint="@color/grid_file_features_background_color"
+            android:orientation="horizontal"
+            android:padding="@dimen/standard_quarter_padding"
+            android:translationZ="4dp"
+            app:layout_constraintBottom_toBottomOf="@+id/thumbnail"
+            app:layout_constraintEnd_toEndOf="parent">
 
 
+            <ImageView
+                tools:visibility="visible"
+                android:id="@+id/favorite_action"
+                android:layout_width="@dimen/grid_layout_item_size"
+                android:layout_height="@dimen/grid_layout_item_size"
+                android:layout_marginEnd="@dimen/grid_layout_margin_end"
+                android:contentDescription="@string/favorite_icon"
+                android:src="@drawable/favorite" />
+
+            <ImageView
+                android:id="@+id/videoOverlay"
+                android:layout_width="@dimen/grid_layout_item_size"
+                android:layout_height="@dimen/grid_layout_item_size"
+                android:layout_marginEnd="@dimen/grid_layout_margin_end"
+                android:contentDescription="@string/video_overlay_icon"
+                android:src="@drawable/video_white"
+                android:visibility="gone"
+                app:tint="@color/grid_file_features_icon_color"
+                tools:visibility="visible" />
 
 
             <ImageView
             <ImageView
                 android:id="@+id/sharedIcon"
                 android:id="@+id/sharedIcon"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="top|end"
-                android:layout_marginTop="@dimen/grid_item_shared_icon_layout_top_margin"
-                android:layout_marginEnd="@dimen/standard_quarter_margin"
+                android:layout_width="@dimen/grid_layout_item_size"
+                android:layout_height="@dimen/grid_layout_item_size"
+                android:layout_marginEnd="@dimen/grid_layout_margin_end"
                 android:contentDescription="@string/shared_icon_shared_via_link"
                 android:contentDescription="@string/shared_icon_shared_via_link"
-                android:src="@drawable/shared_via_link" />
+                android:src="@drawable/shared_via_link"
+                app:tint="@color/grid_file_features_icon_color"
+                tools:visibility="visible" />
 
 
             <ImageView
             <ImageView
                 android:id="@+id/unreadComments"
                 android:id="@+id/unreadComments"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="top|end"
-                android:layout_marginTop="@dimen/grid_item_shared_icon_layout_top_margin"
-                android:layout_marginEnd="@dimen/standard_quarter_margin"
+                android:layout_width="@dimen/grid_layout_item_size"
+                android:layout_height="@dimen/grid_layout_item_size"
+                tools:ignore="TouchTargetSizeCheck"
+                android:layout_marginEnd="@dimen/grid_layout_margin_end"
                 android:clickable="true"
                 android:clickable="true"
                 android:contentDescription="@string/unread_comments"
                 android:contentDescription="@string/unread_comments"
                 android:focusable="true"
                 android:focusable="true"
                 android:src="@drawable/ic_comment_grid"
                 android:src="@drawable/ic_comment_grid"
-                android:visibility="gone" />
+                android:visibility="gone"
+                app:tint="@color/grid_file_features_icon_color"
+                tools:visibility="visible" />
 
 
             <ImageView
             <ImageView
                 android:id="@+id/localFileIndicator"
                 android:id="@+id/localFileIndicator"
-                android:layout_width="@dimen/grid_item_local_file_indicator_layout_width"
-                android:layout_height="@dimen/grid_item_local_file_indicator_layout_height"
-                android:layout_gravity="bottom|end"
-                android:layout_marginTop="@dimen/standard_quarter_margin"
-                android:layout_marginEnd="@dimen/standard_quarter_margin"
-                android:layout_marginBottom="@dimen/standard_quarter_margin"
+                android:layout_width="@dimen/grid_layout_item_size"
+                android:layout_height="@dimen/grid_layout_item_size"
+                android:layout_marginEnd="@dimen/grid_layout_margin_end"
                 android:contentDescription="@string/synced_icon"
                 android:contentDescription="@string/synced_icon"
-                android:src="@drawable/ic_synced" />
+                android:src="@drawable/ic_synced"
+                tools:visibility="visible" />
+
+        </LinearLayout>
+
+        <ImageView
+            android:id="@+id/custom_checkbox"
+            android:layout_width="@dimen/grid_checkbox_size"
+            android:layout_height="@dimen/grid_checkbox_size"
+            android:layout_marginStart="@dimen/grid_checkbox_margin"
+            android:layout_marginTop="@dimen/grid_checkbox_margin"
+            android:contentDescription="@string/checkbox"
+            android:src="@android:drawable/checkbox_off_background"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent"
+            tools:visibility="visible" />
+
+        <TextView
+            android:id="@+id/Filename"
+            android:layout_width="@dimen/grid_filename_width"
+            android:layout_height="@dimen/grid_bottom_view_height"
+            android:layout_gravity="center"
+            android:layout_marginBottom="@dimen/grid_bottom_view_margin_bottom"
+            android:ellipsize="middle"
+            android:gravity="center"
+            android:singleLine="true"
+            android:text="@string/placeholder_filename"
+            android:textColor="@color/text_color"
+            android:textSize="@dimen/grid_item_text_size"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            tools:visibility="visible" />
+
+        <ImageButton
+            android:id="@+id/more"
+            android:layout_width="@dimen/grid_bottom_view_height"
+            android:layout_height="@dimen/grid_bottom_view_height"
+            android:layout_marginBottom="@dimen/grid_bottom_view_margin_bottom"
+            android:layout_marginEnd="@dimen/grid_bottom_view_margin_end"
+            android:translationZ="2dp"
+            tools:ignore="TouchTargetSizeCheck"
+            android:layout_gravity="center"
+            android:background="@color/transparent"
+            android:contentDescription="@string/overflow_menu"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:srcCompat="@drawable/ic_dots_vertical" />
 
 
-            <ImageView
-                android:id="@+id/custom_checkbox"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center_vertical|top"
-                android:layout_marginLeft="@dimen/standard_quarter_margin"
-                android:layout_marginRight="@dimen/standard_quarter_margin"
-                android:contentDescription="@string/checkbox"
-                android:src="@android:drawable/checkbox_off_background" />
-
-        </FrameLayout>
     </androidx.constraintlayout.widget.ConstraintLayout>
     </androidx.constraintlayout.widget.ConstraintLayout>
 
 
-    <TextView
-        android:id="@+id/Filename"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginLeft="@dimen/standard_quarter_margin"
-        android:layout_marginRight="@dimen/standard_quarter_margin"
-        android:ellipsize="middle"
-        android:gravity="center_horizontal"
-        android:singleLine="true"
-        android:text="@string/placeholder_filename"
-        android:textColor="@color/text_color"
-        android:textSize="@dimen/grid_item_text_size" />
-
-</com.owncloud.android.ui.SquareLinearLayout>
+</LinearLayout>

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

@@ -23,6 +23,8 @@
     <color name="white">#ffffff</color>
     <color name="white">#ffffff</color>
     <color name="white_helper_text">#B3FFFFFF</color>
     <color name="white_helper_text">#B3FFFFFF</color>
     <color name="text_color">#333333</color>
     <color name="text_color">#333333</color>
+    <color name="grid_file_features_icon_color">#303034</color>
+    <color name="grid_file_features_background_color">#E9E8EB</color>
     <color name="drawer_text_color">@color/secondary_text_color</color>
     <color name="drawer_text_color">@color/secondary_text_color</color>
     <color name="text_color_inverse">#ffffff</color>
     <color name="text_color_inverse">#ffffff</color>
     <color name="disabled_text">#ff888888</color>
     <color name="disabled_text">#ff888888</color>

+ 16 - 6
app/src/main/res/values/dims.xml

@@ -40,6 +40,11 @@
     <dimen name="standard_double_margin">32dp</dimen>
     <dimen name="standard_double_margin">32dp</dimen>
     <dimen name="standard_half_margin">8dp</dimen>
     <dimen name="standard_half_margin">8dp</dimen>
     <dimen name="standard_quarter_margin">4dp</dimen>
     <dimen name="standard_quarter_margin">4dp</dimen>
+    <dimen name="grid_layout_item_size">10dp</dimen>
+    <dimen name="grid_layout_file_features_margin_end">24dp</dimen>
+    <dimen name="grid_layout_margin_end">2dp</dimen>
+    <dimen name="grid_layout_margin_bottom">16dp</dimen>
+    <dimen name="grid_sync_item_layout_next_text_size">22sp</dimen>
     <dimen name="button_width">140dp</dimen>
     <dimen name="button_width">140dp</dimen>
     <dimen name="button_extra_width">180dp</dimen>
     <dimen name="button_extra_width">180dp</dimen>
     <dimen name="standard_eighth_margin">2dp</dimen>
     <dimen name="standard_eighth_margin">2dp</dimen>
@@ -103,6 +108,17 @@
     <dimen name="activity_row_layout_height">48dp</dimen>
     <dimen name="activity_row_layout_height">48dp</dimen>
     <dimen name="notification_icon_width">24dp</dimen>
     <dimen name="notification_icon_width">24dp</dimen>
     <dimen name="notification_icon_height">24dp</dimen>
     <dimen name="notification_icon_height">24dp</dimen>
+    <dimen name="grid_container_margin">4dp</dimen>
+    <dimen name="selected_grid_container_radius">4dp</dimen>
+    <dimen name="grid_checkbox_size">18dp</dimen>
+    <dimen name="grid_checkbox_margin">6dp</dimen>
+    <dimen name="grid_thumbnail_margin_bottom">18dp</dimen>
+    <dimen name="grid_bottom_view_margin_bottom">10dp</dimen>
+    <dimen name="grid_bottom_view_margin_end">6dp</dimen>
+    <dimen name="grid_bottom_view_height">20dp</dimen>
+    <dimen name="grid_container_width">130dp</dimen>
+    <dimen name="grid_container_height">120dp</dimen>
+    <dimen name="grid_filename_width">80dp</dimen>
     <dimen name="notification_icon_layout_right_end_margin">21dp</dimen>
     <dimen name="notification_icon_layout_right_end_margin">21dp</dimen>
     <dimen name="notification_list_item_grid_layout_left_start_margin">-8dp</dimen>
     <dimen name="notification_list_item_grid_layout_left_start_margin">-8dp</dimen>
     <dimen name="uploader_list_separator_height">1dp</dimen>
     <dimen name="uploader_list_separator_height">1dp</dimen>
@@ -110,12 +126,6 @@
     <dimen name="contactlist_item_icon_layout_height">40dp</dimen>
     <dimen name="contactlist_item_icon_layout_height">40dp</dimen>
     <dimen name="empty_list_icon_layout_width">72dp</dimen>
     <dimen name="empty_list_icon_layout_width">72dp</dimen>
     <dimen name="empty_list_icon_layout_height">72dp</dimen>
     <dimen name="empty_list_icon_layout_height">72dp</dimen>
-    <dimen name="grid_image_icon_margin">14dp</dimen>
-    <dimen name="grid_image_icon_padding">14dp</dimen>
-    <dimen name="grid_item_shared_icon_layout_top_margin">24dp</dimen>
-    <dimen name="grid_item_local_file_indicator_layout_width">16dp</dimen>
-    <dimen name="grid_item_local_file_indicator_layout_height">16dp</dimen>
-    <dimen name="grid_sync_item_layout_next_text_size">22sp</dimen>
     <dimen name="grid_sync_item_layout_counter_text_size">22sp</dimen>
     <dimen name="grid_sync_item_layout_counter_text_size">22sp</dimen>
     <dimen name="list_item_favorite_action_layout_width">14dp</dimen>
     <dimen name="list_item_favorite_action_layout_width">14dp</dimen>
     <dimen name="list_item_favorite_action_layout_height">14dp</dimen>
     <dimen name="list_item_favorite_action_layout_height">14dp</dimen>

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

@@ -808,6 +808,7 @@
     <string name="no_map_app_availble">No App available to handle maps</string>
     <string name="no_map_app_availble">No App available to handle maps</string>
     <string name="share_via_link_hide_download">Hide download</string>
     <string name="share_via_link_hide_download">Hide download</string>
     <string name="unread_comments">Unread comments exist</string>
     <string name="unread_comments">Unread comments exist</string>
+    <string name="grid_file_features_live_photo_content_description">This icon indicates availability of live photo</string>
     <string name="richdocuments_failed_to_load_document">Failed to load document!</string>
     <string name="richdocuments_failed_to_load_document">Failed to load document!</string>
     <string name="create_new_document">Create new document</string>
     <string name="create_new_document">Create new document</string>
     <string name="create_new_spreadsheet">Create new spreadsheet</string>
     <string name="create_new_spreadsheet">Create new spreadsheet</string>