浏览代码

Merge pull request #3120 from nextcloud/showComments

Show unread comments count
Andy Scherzinger 6 年之前
父节点
当前提交
6daf772501

+ 4 - 0
drawable_resources/comment.svg

@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16" version="1.1" viewbox="0 0 16 16">
+    <path
+        d="M8 1.5C3.582 1.5 0 3.962 0 7s3.582 5.5 8 5.5c.25 0 .49-.016.734-.03L13 16v-4.703c1.83-1.008 3-2.56 3-4.297 0-3.038-3.582-5.5-8-5.5z" />
+</svg>

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

@@ -204,6 +204,7 @@ public class FileDataStorageManager {
         cv.put(ProviderTableMeta.FILE_UPDATE_THUMBNAIL, file.isUpdateThumbnailNeeded());
         cv.put(ProviderTableMeta.FILE_IS_DOWNLOADING, file.isDownloading());
         cv.put(ProviderTableMeta.FILE_ETAG_IN_CONFLICT, file.getEtagInConflict());
+        cv.put(ProviderTableMeta.FILE_UNREAD_COMMENTS_COUNT, file.getUnreadCommentsCount());
 
         boolean sameRemotePath = fileExists(file.getRemotePath());
         if (sameRemotePath ||
@@ -441,6 +442,8 @@ public class FileDataStorageManager {
         cv.put(ProviderTableMeta.FILE_REMOTE_ID, folder.getRemoteId());
         cv.put(ProviderTableMeta.FILE_FAVORITE, folder.isFavorite());
         cv.put(ProviderTableMeta.FILE_IS_ENCRYPTED, folder.isEncrypted());
+        cv.put(ProviderTableMeta.FILE_UNREAD_COMMENTS_COUNT, folder.getUnreadCommentsCount());
+
         return cv;
     }
 
@@ -475,6 +478,8 @@ public class FileDataStorageManager {
         cv.put(ProviderTableMeta.FILE_IS_ENCRYPTED, file.isEncrypted());
         cv.put(ProviderTableMeta.FILE_MOUNT_TYPE, file.getMountType().ordinal());
         cv.put(ProviderTableMeta.FILE_HAS_PREVIEW, file.isPreviewAvailable() ? 1 : 0);
+        cv.put(ProviderTableMeta.FILE_UNREAD_COMMENTS_COUNT, file.getUnreadCommentsCount());
+
         return cv;
     }
 
@@ -969,7 +974,9 @@ public class FileDataStorageManager {
             file.setMountType(WebdavEntry.MountType.values()[c.getInt(
                     c.getColumnIndex(ProviderTableMeta.FILE_MOUNT_TYPE))]);
             file.setPreviewAvailable(c.getInt(c.getColumnIndex(ProviderTableMeta.FILE_HAS_PREVIEW)) == 1);
+            file.setUnreadCommentsCount(c.getInt(c.getColumnIndex(ProviderTableMeta.FILE_UNREAD_COMMENTS_COUNT)));
         }
+
         return file;
     }
 

+ 6 - 9
src/main/java/com/owncloud/android/datamodel/OCFile.java

@@ -77,25 +77,22 @@ public class OCFile implements Parcelable, Comparable<OCFile>, ServerFileInterfa
     @Getter @Setter private long lastSyncDateForProperties;
     @Getter @Setter private long lastSyncDateForData;
     @Getter @Setter private boolean availableOffline;
-    @Getter
-    @Setter
-    private boolean previewAvailable;
+    @Getter @Setter private boolean previewAvailable;
     @Getter private String etag;
     @Getter @Setter private boolean sharedViaLink;
     @Getter @Setter private String publicLink;
     @Getter @Setter private String permissions;
-    @Getter
-    @Setter
-    private String remoteId; // The fileid namespaced by the instance fileId, globally unique
+    @Getter @Setter private String remoteId; // The fileid namespaced by the instance fileId, globally unique
     @Getter @Setter private boolean updateThumbnailNeeded;
     @Getter @Setter private boolean downloading;
-    @Getter
-    @Setter
-    private String etagInConflict; // Only saves file etag in the server, when there is a conflict
+    @Getter @Setter private String etagInConflict; // Only saves file etag in the server, when there is a conflict
     @Getter @Setter private boolean sharedWithSharee;
     @Getter @Setter private boolean favorite;
     @Getter @Setter private boolean encrypted;
     @Getter @Setter private WebdavEntry.MountType mountType;
+    @Getter
+    @Setter
+    private int unreadCommentsCount;
 
     /**
      * URI to the local path of the file contents, if stored in the device; cached after first call

+ 8 - 7
src/main/java/com/owncloud/android/db/ProviderMeta.java

@@ -32,7 +32,7 @@ import com.owncloud.android.MainApp;
 public class ProviderMeta {
 
     public static final String DB_NAME = "filelist";
-    public static final int DB_VERSION = 39;
+    public static final int DB_VERSION = 40;
 
     private ProviderMeta() {
     }
@@ -104,14 +104,15 @@ public class ProviderMeta {
         public static final String FILE_IS_ENCRYPTED = "is_encrypted";
         public static final String FILE_MOUNT_TYPE = "mount_type";
         public static final String FILE_HAS_PREVIEW = "has_preview";
+        public static final String FILE_UNREAD_COMMENTS_COUNT = "unread_comments_count";
 
-        public static final String [] FILE_ALL_COLUMNS = {_ID, FILE_PARENT, FILE_NAME
-               , FILE_CREATION, FILE_MODIFIED,
-                FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA, FILE_CONTENT_LENGTH, FILE_CONTENT_TYPE, FILE_STORAGE_PATH,
-                FILE_PATH, FILE_ACCOUNT_OWNER, FILE_LAST_SYNC_DATE, FILE_LAST_SYNC_DATE_FOR_DATA, FILE_KEEP_IN_SYNC,
-                FILE_ETAG, FILE_SHARED_VIA_LINK, FILE_SHARED_WITH_SHAREE, FILE_PUBLIC_LINK, FILE_PERMISSIONS,
+        public static final String[] FILE_ALL_COLUMNS = {
+            _ID, FILE_PARENT, FILE_NAME, FILE_CREATION, FILE_MODIFIED,
+            FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA, FILE_CONTENT_LENGTH, FILE_CONTENT_TYPE, FILE_STORAGE_PATH,
+            FILE_PATH, FILE_ACCOUNT_OWNER, FILE_LAST_SYNC_DATE, FILE_LAST_SYNC_DATE_FOR_DATA, FILE_KEEP_IN_SYNC,
+            FILE_ETAG, FILE_SHARED_VIA_LINK, FILE_SHARED_WITH_SHAREE, FILE_PUBLIC_LINK, FILE_PERMISSIONS,
             FILE_REMOTE_ID, FILE_UPDATE_THUMBNAIL, FILE_IS_DOWNLOADING, FILE_ETAG_IN_CONFLICT, FILE_FAVORITE,
-            FILE_HAS_PREVIEW};
+            FILE_IS_ENCRYPTED, FILE_MOUNT_TYPE, FILE_HAS_PREVIEW, FILE_UNREAD_COMMENTS_COUNT};
 
         public static final String FILE_DEFAULT_SORT_ORDER = FILE_NAME + " collate nocase asc";
 

+ 21 - 2
src/main/java/com/owncloud/android/providers/FileContentProvider.java

@@ -749,8 +749,9 @@ public class FileContentProvider extends ContentProvider {
                 + ProviderTableMeta.FILE_IS_ENCRYPTED + INTEGER // boolean
                 + ProviderTableMeta.FILE_ETAG_IN_CONFLICT + TEXT
                 + ProviderTableMeta.FILE_SHARED_WITH_SHAREE + INTEGER
-            + ProviderTableMeta.FILE_MOUNT_TYPE + INTEGER
-            + ProviderTableMeta.FILE_HAS_PREVIEW + " INTEGER);"
+                + ProviderTableMeta.FILE_MOUNT_TYPE + INTEGER
+                + ProviderTableMeta.FILE_HAS_PREVIEW + INTEGER
+                + ProviderTableMeta.FILE_UNREAD_COMMENTS_COUNT + " INTEGER);"
         );
     }
 
@@ -1844,6 +1845,24 @@ public class FileContentProvider extends ContentProvider {
             if (!upgraded) {
                 Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion));
             }
+
+            if (oldVersion < 40 && newVersion >= 40) {
+                Log_OC.i(SQL, "Entering in the #40 add unreadCommentsCount to file table");
+                db.beginTransaction();
+                try {
+                    db.execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME +
+                            ADD_COLUMN + ProviderTableMeta.FILE_UNREAD_COMMENTS_COUNT + " INTEGER ");
+
+                    upgraded = true;
+                    db.setTransactionSuccessful();
+                } finally {
+                    db.endTransaction();
+                }
+            }
+
+            if (!upgraded) {
+                Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion));
+            }
         }
 
         @Override

+ 45 - 11
src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java

@@ -181,6 +181,24 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
         new Handler(Looper.getMainLooper()).post(this::notifyDataSetChanged);
     }
 
+    public void refreshCommentsCount(String fileId) {
+        for (OCFile file : mFiles) {
+            if (file.getRemoteId().equals(fileId)) {
+                file.setUnreadCommentsCount(0);
+                break;
+            }
+        }
+
+        for (OCFile file : mFilesAll) {
+            if (file.getRemoteId().equals(fileId)) {
+                file.setUnreadCommentsCount(0);
+                break;
+            }
+        }
+
+        new Handler(Looper.getMainLooper()).post(this::notifyDataSetChanged);
+    }
+
     public void setEncryptionAttributeForItemID(String fileId, boolean encrypted) {
         int filesSize = mFiles.size();
         for (int i = 0; i < filesSize; i++) {
@@ -275,6 +293,15 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
                         ocFileListFragmentInterface.onLongItemClicked(file));
             }
 
+            // unread comments
+            if (file.getUnreadCommentsCount() > 0) {
+                gridViewHolder.unreadComments.setVisibility(View.VISIBLE);
+                gridViewHolder.unreadComments.setOnClickListener(view -> ocFileListFragmentInterface
+                    .showActivityDetailView(file));
+            } else {
+                gridViewHolder.unreadComments.setVisibility(View.GONE);
+            }
+
             if (holder instanceof OCFileListItemViewHolder) {
                 OCFileListItemViewHolder itemViewHolder = (OCFileListItemViewHolder) holder;
 
@@ -478,19 +505,24 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
 
     private void showShareIcon(OCFileListGridImageViewHolder gridViewHolder, OCFile file) {
         ImageView sharedIconView = gridViewHolder.shared;
-        sharedIconView.setVisibility(View.VISIBLE);
-
-        if (file.isSharedWithSharee() || file.isSharedWithMe()) {
-            sharedIconView.setImageResource(R.drawable.shared_via_users);
-            sharedIconView.setContentDescription(mContext.getString(R.string.shared_icon_shared));
-        } else if (file.isSharedViaLink()) {
-            sharedIconView.setImageResource(R.drawable.shared_via_link);
-            sharedIconView.setContentDescription(mContext.getString(R.string.shared_icon_shared_via_link));
+
+        if (gridViewHolder instanceof OCFileListItemViewHolder || file.getUnreadCommentsCount() == 0) {
+            sharedIconView.setVisibility(View.VISIBLE);
+
+            if (file.isSharedWithSharee() || file.isSharedWithMe()) {
+                sharedIconView.setImageResource(R.drawable.shared_via_users);
+                sharedIconView.setContentDescription(mContext.getString(R.string.shared_icon_shared));
+            } else if (file.isSharedViaLink()) {
+                sharedIconView.setImageResource(R.drawable.shared_via_link);
+                sharedIconView.setContentDescription(mContext.getString(R.string.shared_icon_shared_via_link));
+            } else {
+                sharedIconView.setImageResource(R.drawable.ic_unshared);
+                sharedIconView.setContentDescription(mContext.getString(R.string.shared_icon_share));
+            }
+            sharedIconView.setOnClickListener(view -> ocFileListFragmentInterface.onShareIconClick(file));
         } else {
-            sharedIconView.setImageResource(R.drawable.ic_unshared);
-            sharedIconView.setContentDescription(mContext.getString(R.string.shared_icon_share));
+            sharedIconView.setVisibility(View.GONE);
         }
-        sharedIconView.setOnClickListener(view -> ocFileListFragmentInterface.onShareIconClick(file));
     }
 
     /**
@@ -820,6 +852,7 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
         private final ImageView localFileIndicator;
         private final ImageView shared;
         private final ImageView checkbox;
+        final ImageView unreadComments;
         private final LinearLayout itemLayout;
 
         private OCFileListGridImageViewHolder(View itemView) {
@@ -831,6 +864,7 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
             localFileIndicator = itemView.findViewById(R.id.localFileIndicator);
             shared = itemView.findViewById(R.id.sharedIcon);
             checkbox = itemView.findViewById(R.id.custom_checkbox);
+            unreadComments = itemView.findViewById(R.id.unreadComments);
             itemLayout = itemView.findViewById(R.id.ListItemLayout);
         }
     }

+ 33 - 0
src/main/java/com/owncloud/android/ui/events/CommentsEvent.java

@@ -0,0 +1,33 @@
+/*
+ * Nextcloud Android client application
+ *
+ * @author Tobias Kaminsky
+ * Copyright (C) 2018 Tobias Kaminsky
+ * Copyright (C) 2018 Nextcloud GmbH.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package com.owncloud.android.ui.events;
+
+/**
+ * Event for refreshing comment state of a file
+ */
+public class CommentsEvent {
+    public final String remoteId;
+
+    public CommentsEvent(String remoteId) {
+        this.remoteId = remoteId;
+    }
+}

+ 17 - 0
src/main/java/com/owncloud/android/ui/fragment/FileDetailActivitiesFragment.java

@@ -50,6 +50,7 @@ import com.owncloud.android.lib.common.operations.RemoteOperationResult;
 import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.lib.resources.activities.GetActivitiesRemoteOperation;
 import com.owncloud.android.lib.resources.activities.model.RichObject;
+import com.owncloud.android.lib.resources.comments.MarkCommentsAsReadRemoteOperation;
 import com.owncloud.android.lib.resources.files.ReadFileVersionsRemoteOperation;
 import com.owncloud.android.lib.resources.files.model.FileVersion;
 import com.owncloud.android.lib.resources.status.OCCapability;
@@ -58,12 +59,14 @@ import com.owncloud.android.operations.CommentFileOperation;
 import com.owncloud.android.ui.activity.ComponentsGetter;
 import com.owncloud.android.ui.activity.FileActivity;
 import com.owncloud.android.ui.adapter.ActivityAndVersionListAdapter;
+import com.owncloud.android.ui.events.CommentsEvent;
 import com.owncloud.android.ui.helpers.FileOperationsHelper;
 import com.owncloud.android.ui.interfaces.ActivityListInterface;
 import com.owncloud.android.ui.interfaces.VersionListInterface;
 import com.owncloud.android.utils.ThemeUtils;
 
 import org.apache.commons.httpclient.HttpStatus;
+import org.greenrobot.eventbus.EventBus;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -354,6 +357,20 @@ public class FileDetailActivitiesFragment extends Fragment implements ActivityLi
         t.start();
     }
 
+    public void markCommentsAsRead() {
+        new Thread(() -> {
+            if (file.getUnreadCommentsCount() > 0) {
+                MarkCommentsAsReadRemoteOperation unreadOperation = new MarkCommentsAsReadRemoteOperation(
+                    file.getLocalId());
+                RemoteOperationResult remoteOperationResult = unreadOperation.execute(ownCloudClient);
+
+                if (remoteOperationResult.isSuccess()) {
+                    EventBus.getDefault().post(new CommentsEvent(file.getRemoteId()));
+                }
+            }
+        }).start();
+    }
+
     private void populateList(List<Object> activities, boolean clear) {
         adapter.setActivityAndVersionItems(activities, ownCloudClient, clear);
     }

+ 14 - 1
src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java

@@ -277,11 +277,24 @@ public class FileDetailFragment extends FileFragment implements OnClickListener
 
         final FileDetailTabAdapter adapter = new FileDetailTabAdapter(getFragmentManager(), getFile(), account);
         viewPager.setAdapter(adapter);
-        viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
+        viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout) {
+            @Override
+            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+                if (activeTab == 0) {
+                    getFileDetailActivitiesFragment().markCommentsAsRead();
+                }
+
+                super.onPageScrolled(position, positionOffset, positionOffsetPixels);
+            }
+        });
         tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
             @Override
             public void onTabSelected(TabLayout.Tab tab) {
                 viewPager.setCurrentItem(tab.getPosition());
+
+                if (tab.getPosition() == 0) {
+                    getFileDetailActivitiesFragment().markCommentsAsRead();
+                }
             }
 
             @Override

+ 16 - 0
src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java

@@ -84,6 +84,7 @@ import com.owncloud.android.ui.dialog.RemoveFilesDialogFragment;
 import com.owncloud.android.ui.dialog.RenameFileDialogFragment;
 import com.owncloud.android.ui.dialog.SetupEncryptionDialogFragment;
 import com.owncloud.android.ui.events.ChangeMenuEvent;
+import com.owncloud.android.ui.events.CommentsEvent;
 import com.owncloud.android.ui.events.DummyDrawerEvent;
 import com.owncloud.android.ui.events.EncryptionEvent;
 import com.owncloud.android.ui.events.FavoriteEvent;
@@ -434,6 +435,16 @@ public class OCFileListFragment extends ExtendedListFragment implements
         }
     }
 
+    @Override
+    public void showShareDetailView(OCFile file) {
+        mContainerActivity.showDetails(file, 1);
+    }
+
+    @Override
+    public void showActivityDetailView(OCFile file) {
+        mContainerActivity.showDetails(file, 0);
+    }
+    
     @Override
     public void onOverflowIconClicked(OCFile file, View view) {
         PopupMenu popup = new PopupMenu(getActivity(), view);
@@ -1379,6 +1390,11 @@ public class OCFileListFragment extends ExtendedListFragment implements
         setFabVisible(true);
     }
 
+    @Subscribe(threadMode = ThreadMode.BACKGROUND)
+    public void onMessageEvent(CommentsEvent event) {
+        mAdapter.refreshCommentsCount(event.remoteId);
+    }
+
     @Subscribe(threadMode = ThreadMode.BACKGROUND)
     public void onMessageEvent(FavoriteEvent event) {
         Account currentAccount = AccountUtils.getCurrentOwnCloudAccount(MainApp.getAppContext());

+ 4 - 0
src/main/java/com/owncloud/android/ui/interfaces/OCFileListFragmentInterface.java

@@ -35,6 +35,10 @@ public interface OCFileListFragmentInterface {
 
     void onShareIconClick(OCFile file);
 
+    void showShareDetailView(OCFile file);
+
+    void showActivityDetailView(OCFile file);
+
     void onOverflowIconClicked(OCFile file, View view);
 
     void onItemClicked(OCFile file);

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

@@ -178,6 +178,7 @@ public final class FileStorageUtils {
         }
         file.setMountType(remote.getMountType());
         file.setPreviewAvailable(remote.hasPreview());
+        file.setUnreadCommentsCount(remote.getUnreadCommentsCount());
 
         return file;
     }

+ 9 - 0
src/main/res/drawable/ic_comment.xml

@@ -0,0 +1,9 @@
+<vector android:height="24dp"
+        android:viewportHeight="16"
+        android:viewportWidth="16"
+        android:width="24dp"
+        xmlns:android="http://schemas.android.com/apk/res/android">
+    <path
+        android:fillColor="#ff757575"
+        android:pathData="M8,1.5C3.582,1.5 0,3.962 0,7s3.582,5.5 8,5.5c0.25,0 0.49,-0.016 0.734,-0.03L13,16v-4.703c1.83,-1.008 3,-2.56 3,-4.297 0,-3.038 -3.582,-5.5 -8,-5.5z"/>
+</vector>

+ 12 - 0
src/main/res/drawable/ic_comment_grid.xml

@@ -0,0 +1,12 @@
+<vector android:height="20dp"
+    android:viewportHeight="16"
+    android:viewportWidth="16"
+    android:width="20dp"
+    xmlns:android="http://schemas.android.com/apk/res/android">
+    <path
+        android:strokeColor="#FFFFFFFF"
+        android:strokeWidth="1"
+        android:strokeMiterLimit="4"
+        android:fillColor="#ff757575"
+        android:pathData="M8,1.5C3.582,1.5 0,3.962 0,7s3.582,5.5 8,5.5c0.25,0 0.49,-0.016 0.734,-0.03L13,16v-4.703c1.83,-1.008 3,-2.56 3,-4.297 0,-3.038 -3.582,-5.5 -8,-5.5z" />
+</vector>

+ 3 - 3
src/main/res/layout/file_details_sharing_fragment.xml

@@ -38,7 +38,7 @@
             android:layout_marginLeft="@dimen/standard_eighth_margin"
             android:layout_marginEnd="@dimen/standard_margin"
             android:layout_marginRight="@dimen/standard_margin"
-            style="@style/ownCloud.SearchView"/>
+            style="@style/ownCloud.SearchView" />
 
         <LinearLayout
             android:id="@+id/share_by_link_container"
@@ -71,7 +71,7 @@
                 android:paddingBottom="@dimen/standard_quarter_margin"
                 android:scaleType="fitStart"
                 android:src="@drawable/ic_content_copy"
-                android:layout_gravity="start|center"/>
+                android:layout_gravity="start|center" />
 
             <androidx.appcompat.widget.AppCompatCheckBox
                 android:id="@+id/share_by_link_allow_editing"
@@ -79,7 +79,7 @@
                 android:layout_height="wrap_content"
                 android:layout_gravity="center_vertical"
                 android:textSize="16sp"
-                android:text="@string/edit_permission_label"/>
+                android:text="@string/edit_permission_label" />
 
             <ImageView
                 android:id="@+id/overflow_menu_share_link"

+ 15 - 1
src/main/res/layout/grid_image.xml

@@ -13,7 +13,7 @@
 
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-  
+
 -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/ListItemLayout"
@@ -59,6 +59,20 @@
             android:contentDescription="@string/shared_icon_shared_via_link"
             android:src="@drawable/shared_via_link" />
 
+        <ImageView
+            android:id="@+id/unreadComments"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="top|end"
+            android:layout_marginEnd="@dimen/standard_quarter_margin"
+            android:layout_marginRight="@dimen/standard_quarter_margin"
+            android:layout_marginTop="@dimen/grid_image_shared_icon_layout_top_margin"
+            android:clickable="true"
+            android:contentDescription="@string/unread_comments"
+            android:focusable="true"
+            android:src="@drawable/ic_comment_grid"
+            android:visibility="gone" />
+
         <ImageView
             android:id="@+id/localFileIndicator"
             android:layout_width="@dimen/grid_image_local_file_indicator_layout_width"

+ 16 - 2
src/main/res/layout/grid_item.xml

@@ -13,7 +13,7 @@
 
   You should have received a copy of the GNU General Public License
   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"
     android:id="@+id/ListItemLayout"
@@ -57,6 +57,20 @@
             android:src="@drawable/shared_via_link"
             android:contentDescription="@string/shared_icon_shared_via_link"/>
 
+        <ImageView
+            android:id="@+id/unreadComments"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:clickable="true"
+            android:contentDescription="@string/unread_comments"
+            android:focusable="true"
+            android:layout_gravity="top|end"
+            android:layout_marginTop="@dimen/grid_item_shared_icon_layout_top_margin"
+            android:layout_marginRight="@dimen/standard_quarter_margin"
+            android:layout_marginEnd="@dimen/standard_quarter_margin"
+            android:src="@drawable/ic_comment_grid"
+            android:visibility="gone" />
+
         <ImageView
             android:id="@+id/localFileIndicator"
             android:layout_width="@dimen/grid_item_local_file_indicator_layout_width"
@@ -105,4 +119,4 @@
         android:textColor="@color/textColor"
         android:textSize="@dimen/grid_item_text_size" />
 
-</com.owncloud.android.ui.SquareLinearLayout>
+</com.owncloud.android.ui.SquareLinearLayout>

+ 17 - 0
src/main/res/layout/list_item.xml

@@ -152,11 +152,28 @@
         android:paddingRight="@dimen/zero"
         android:paddingStart="@dimen/standard_half_padding">
 
+        <ImageView
+            android:id="@+id/unreadComments"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:layout_centerVertical="true"
+            android:clickable="true"
+            android:contentDescription="@string/unread_comments"
+            android:focusable="true"
+            android:paddingEnd="@dimen/list_item_share_right_margin"
+            android:paddingLeft="@dimen/standard_half_padding"
+            android:paddingRight="@dimen/list_item_share_right_margin"
+            android:paddingStart="@dimen/standard_half_padding"
+            android:src="@drawable/ic_comment"
+            android:visibility="gone"/>
+
         <ImageView
             android:id="@+id/sharedIcon"
             android:layout_width="wrap_content"
             android:layout_height="match_parent"
             android:layout_centerVertical="true"
+            android:layout_toEndOf="@id/unreadComments"
+            android:layout_toRightOf="@id/unreadComments"
             android:clickable="true"
             android:contentDescription="@string/shared_icon_share"
             android:focusable="true"

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

@@ -828,6 +828,7 @@
     <string name="no_browser_available">No app available to handle links</string>
     <string name="no_pdf_app_available">No App available to handle PDF</string>
     <string name="share_via_link_hide_download">Hide download</string>
+    <string name="unread_comments">Unread comments exist</string>
 
     <string name="richdocuments_failed_to_load_document">Failed to load document!</string>
     <string name="create_new_document">Create new document</string>