Эх сурвалжийг харах

show unread comments

Signed-off-by: tobiasKaminsky <tobias@kaminsky.me>
tobiasKaminsky 6 жил өмнө
parent
commit
cad6cd6a19

+ 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

+ 28 - 0
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++) {
@@ -278,6 +296,14 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
             if (holder instanceof OCFileListItemViewHolder) {
                 OCFileListItemViewHolder itemViewHolder = (OCFileListItemViewHolder) holder;
 
+                if (file.getUnreadCommentsCount() > 0) {
+                    itemViewHolder.unreadComments.setVisibility(View.VISIBLE);
+                    itemViewHolder.unreadComments.setOnClickListener(view ->
+                            ocFileListFragmentInterface.showActivityDetailView(file));
+                } else {
+                    itemViewHolder.unreadComments.setVisibility(View.GONE);
+                }
+
                 if (onlyOnDevice) {
                     File localFile = new File(file.getStoragePath());
 
@@ -793,6 +819,7 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
         private final TextView fileSize;
         private final TextView lastModification;
         private final ImageView overflowMenu;
+        private final ImageView unreadComments;
 
         private OCFileListItemViewHolder(View itemView) {
             super(itemView);
@@ -800,6 +827,7 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
             fileSize = itemView.findViewById(R.id.file_size);
             lastModification = itemView.findViewById(R.id.last_mod);
             overflowMenu = itemView.findViewById(R.id.overflow_menu);
+            unreadComments = itemView.findViewById(R.id.unreadComments);
         }
     }
 

+ 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;
+    }
+}

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

@@ -58,12 +58,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 +356,19 @@ public class FileDetailActivitiesFragment extends Fragment implements ActivityLi
         t.start();
     }
 
+    public void markCommentsAsRead() {
+        new Thread(() -> {
+            if (file.getUnreadCommentsCount() > 0) {
+                MarkCommentsAsReadOperation unreadOperation = new MarkCommentsAsReadOperation(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="#FF000000"
+        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"

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

@@ -152,11 +152,29 @@
         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:alpha="0.3"
+            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>