Browse Source

add new state manually cancelled

Signed-off-by: Jonas Mayer <jonas.a.mayer@gmx.net>
Jonas Mayer 1 year ago
parent
commit
db7cd0033d

+ 30 - 1
app/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java

@@ -630,6 +630,13 @@ public class UploadsStorageManager extends Observable {
                               ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?", user.getAccountName());
                               ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?", user.getAccountName());
     }
     }
 
 
+    public OCUpload[] getManuallyCancelledUploadsForCurrentAccount() {
+        User user = currentAccountProvider.getUser();
+
+        return getUploads(ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_MANUALLY_CANCELLED.value + AND +
+                              ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?", user.getAccountName());
+    }
+
     /**
     /**
      * Get all uploads which where successfully completed.
      * Get all uploads which where successfully completed.
      */
      */
@@ -700,6 +707,21 @@ public class UploadsStorageManager extends Observable {
         return deleted;
         return deleted;
     }
     }
 
 
+    public long clearManuallyCancelledUploadsForCurrentAccount() {
+        User user = currentAccountProvider.getUser();
+        final long deleted = getDB().delete(
+            ProviderTableMeta.CONTENT_URI_UPLOADS,
+            ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_MANUALLY_CANCELLED.value + AND +
+                ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?", new String[]{user.getAccountName()}
+                                           );
+
+        Log_OC.d(TAG, "delete all manually cancelled uploads");
+        if (deleted > 0) {
+            notifyObserversNow();
+        }
+        return deleted;
+    }
+
     public long clearSuccessfulUploads() {
     public long clearSuccessfulUploads() {
         User user = currentAccountProvider.getUser();
         User user = currentAccountProvider.getUser();
         final long deleted = getDB().delete(
         final long deleted = getDB().delete(
@@ -851,7 +873,12 @@ public class UploadsStorageManager extends Observable {
         /**
         /**
          * Upload was successful.
          * Upload was successful.
          */
          */
-        UPLOAD_SUCCEEDED(2);
+        UPLOAD_SUCCEEDED(2),
+
+        /**
+         * Upload was cancelled by the user.
+         */
+        UPLOAD_MANUALLY_CANCELLED(3);
 
 
         private final int value;
         private final int value;
 
 
@@ -867,6 +894,8 @@ public class UploadsStorageManager extends Observable {
                     return UPLOAD_FAILED;
                     return UPLOAD_FAILED;
                 case 2:
                 case 2:
                     return UPLOAD_SUCCEEDED;
                     return UPLOAD_SUCCEEDED;
+                case 3:
+                    return UPLOAD_MANUALLY_CANCELLED;
             }
             }
             return null;
             return null;
         }
         }

+ 4 - 1
app/src/main/java/com/owncloud/android/db/UploadResult.java

@@ -46,7 +46,8 @@ public enum UploadResult {
     CANNOT_CREATE_FILE(20),
     CANNOT_CREATE_FILE(20),
     LOCAL_STORAGE_NOT_COPIED(21),
     LOCAL_STORAGE_NOT_COPIED(21),
     QUOTA_EXCEEDED(22),
     QUOTA_EXCEEDED(22),
-    SAME_FILE_CONFLICT(23);
+    SAME_FILE_CONFLICT(23),
+    MANUALLY_CANCELLED(24);
 
 
     private final int value;
     private final int value;
 
 
@@ -110,6 +111,8 @@ public enum UploadResult {
                 return QUOTA_EXCEEDED;
                 return QUOTA_EXCEEDED;
             case 23:
             case 23:
                 return SAME_FILE_CONFLICT;
                 return SAME_FILE_CONFLICT;
+            case 24:
+                return MANUALLY_CANCELLED;
         }
         }
         return UNKNOWN;
         return UNKNOWN;
     }
     }

+ 54 - 15
app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java

@@ -33,6 +33,7 @@ import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.net.Uri;
 import android.text.format.DateUtils;
 import android.text.format.DateUtils;
 import android.view.LayoutInflater;
 import android.view.LayoutInflater;
+import android.view.MenuItem;
 import android.view.View;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewGroup;
 import android.widget.PopupMenu;
 import android.widget.PopupMenu;
@@ -122,7 +123,8 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
 
 
         switch (group.type) {
         switch (group.type) {
             case CURRENT, FINISHED -> headerViewHolder.binding.uploadListAction.setImageResource(R.drawable.ic_close);
             case CURRENT, FINISHED -> headerViewHolder.binding.uploadListAction.setImageResource(R.drawable.ic_close);
-            case FAILED -> headerViewHolder.binding.uploadListAction.setImageResource(R.drawable.ic_dots_vertical);
+            case CANCELLED, FAILED -> headerViewHolder.binding.uploadListAction.setImageResource(R.drawable.ic_dots_vertical);
+
         }
         }
 
 
         headerViewHolder.binding.uploadListAction.setOnClickListener(v -> {
         headerViewHolder.binding.uploadListAction.setOnClickListener(v -> {
@@ -143,6 +145,10 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
                     // show popup with option clear or retry filed uploads
                     // show popup with option clear or retry filed uploads
                     createFailedPopupMenu(headerViewHolder);
                     createFailedPopupMenu(headerViewHolder);
                 }
                 }
+                case CANCELLED -> {
+                    // show popup with option clear or retry manually cancelled uploads
+                    createCancelledActionsPopupMenu(headerViewHolder);
+                }
             }
             }
         });
         });
     }
     }
@@ -173,6 +179,30 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
         failedPopup.show();
         failedPopup.show();
     }
     }
 
 
+    public void createCancelledActionsPopupMenu(HeaderViewHolder headerViewHolder){
+        PopupMenu popup = new PopupMenu(MainApp.getAppContext(), headerViewHolder.binding.uploadListAction);
+        popup.inflate(R.menu.upload_list_cancelled_options);
+
+        popup.setOnMenuItemClickListener(i -> {
+            int itemId = i.getItemId();
+
+            if (itemId == R.id.action_upload_list_cancelled_clear) {
+                uploadsStorageManager.clearManuallyCancelledUploadsForCurrentAccount();
+                loadUploadItemsFromDb();
+            } else if (itemId == R.id.action_upload_list_cancelled_resume) {
+
+                new Thread(() -> {
+                    parentActivity.runOnUiThread(this::loadUploadItemsFromDb);
+                    // TODO Do something
+                }).start();
+
+            }
+
+            return true;
+        });
+        popup.show();
+    }
+
     @Override
     @Override
     public void onBindFooterViewHolder(SectionedViewHolder holder, int section) {
     public void onBindFooterViewHolder(SectionedViewHolder holder, int section) {
         // not needed
         // not needed
@@ -197,7 +227,7 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
         this.clock = clock;
         this.clock = clock;
         this.viewThemeUtils = viewThemeUtils;
         this.viewThemeUtils = viewThemeUtils;
 
 
-        uploadGroups = new UploadGroup[3];
+        uploadGroups = new UploadGroup[4];
 
 
         shouldShowHeadersForEmptySections(false);
         shouldShowHeadersForEmptySections(false);
 
 
@@ -225,6 +255,14 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
             }
             }
         };
         };
 
 
+        uploadGroups[3] = new UploadGroup(Type.CANCELLED,
+                                          parentActivity.getString(R.string.upload_manually_cancelled)) {
+            @Override
+            public void refresh() {
+                fixAndSortItems(uploadsStorageManager.getManuallyCancelledUploadsForCurrentAccount());
+            }
+        };
+
         showUser = accountManager.getAccounts().length > 1;
         showUser = accountManager.getAccounts().length > 1;
 
 
         loadUploadItemsFromDb();
         loadUploadItemsFromDb();
@@ -655,7 +693,7 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
                     status = parentActivity.getString(R.string.uploads_view_upload_status_succeeded);
                     status = parentActivity.getString(R.string.uploads_view_upload_status_succeeded);
                 }
                 }
             }
             }
-            case UPLOAD_FAILED -> status = getUploadFailedStatusText(upload.getLastResult());
+            case UPLOAD_FAILED, UPLOAD_MANUALLY_CANCELLED -> status = getUploadFailedStatusText(upload.getLastResult());
             default -> status = "Uncontrolled status: " + upload.getUploadStatus();
             default -> status = "Uncontrolled status: " + upload.getUploadStatus();
         }
         }
         return status;
         return status;
@@ -709,8 +747,8 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
             case SSL_RECOVERABLE_PEER_UNVERIFIED:
             case SSL_RECOVERABLE_PEER_UNVERIFIED:
                 status =
                 status =
                     parentActivity.getString(
                     parentActivity.getString(
-                        R.string.uploads_view_upload_status_failed_ssl_certificate_not_trusted
-                                            );
+                                R.string.uploads_view_upload_status_failed_ssl_certificate_not_trusted
+                        );
                 break;
                 break;
             case UNKNOWN:
             case UNKNOWN:
                 status = parentActivity.getString(R.string.uploads_view_upload_status_unknown_fail);
                 status = parentActivity.getString(R.string.uploads_view_upload_status_unknown_fail);
@@ -720,7 +758,7 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
                 break;
                 break;
             case DELAYED_IN_POWER_SAVE_MODE:
             case DELAYED_IN_POWER_SAVE_MODE:
                 status = parentActivity.getString(
                 status = parentActivity.getString(
-                    R.string.uploads_view_upload_status_waiting_exit_power_save_mode);
+                        R.string.uploads_view_upload_status_waiting_exit_power_save_mode);
                 break;
                 break;
             case VIRUS_DETECTED:
             case VIRUS_DETECTED:
                 status = parentActivity.getString(R.string.uploads_view_upload_status_virus_detected);
                 status = parentActivity.getString(R.string.uploads_view_upload_status_virus_detected);
@@ -743,6 +781,9 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
             case QUOTA_EXCEEDED:
             case QUOTA_EXCEEDED:
                 status = parentActivity.getString(R.string.upload_quota_exceeded);
                 status = parentActivity.getString(R.string.upload_quota_exceeded);
                 break;
                 break;
+            case MANUALLY_CANCELLED:
+                status = parentActivity.getString(R.string.upload_manually_cancelled);
+                break;
             default:
             default:
                 status = parentActivity.getString(R.string.upload_unknown_error);
                 status = parentActivity.getString(R.string.upload_unknown_error);
                 break;
                 break;
@@ -795,17 +836,17 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
      */
      */
     private void onUploadedItemClick(OCUpload upload) {
     private void onUploadedItemClick(OCUpload upload) {
         final OCFile file = parentActivity.getStorageManager().getFileByEncryptedRemotePath(upload.getRemotePath());
         final OCFile file = parentActivity.getStorageManager().getFileByEncryptedRemotePath(upload.getRemotePath());
-        if (file == null) {
+        if (file == null){
             DisplayUtils.showSnackMessage(parentActivity, R.string.error_retrieving_file);
             DisplayUtils.showSnackMessage(parentActivity, R.string.error_retrieving_file);
             Log_OC.i(TAG, "Could not find uploaded file on remote.");
             Log_OC.i(TAG, "Could not find uploaded file on remote.");
             return;
             return;
         }
         }
 
 
-        if (PreviewImageFragment.canBePreviewed(file)) {
+        if (PreviewImageFragment.canBePreviewed(file)){
             //show image preview and stay in uploads tab
             //show image preview and stay in uploads tab
             Intent intent = FileDisplayActivity.openFileIntent(parentActivity, parentActivity.getUser().get(), file);
             Intent intent = FileDisplayActivity.openFileIntent(parentActivity, parentActivity.getUser().get(), file);
             parentActivity.startActivity(intent);
             parentActivity.startActivity(intent);
-        } else {
+        }else{
             Intent intent = new Intent(parentActivity, FileDisplayActivity.class);
             Intent intent = new Intent(parentActivity, FileDisplayActivity.class);
             intent.setAction(Intent.ACTION_VIEW);
             intent.setAction(Intent.ACTION_VIEW);
             intent.putExtra(FileDisplayActivity.KEY_FILE_PATH, upload.getRemotePath());
             intent.putExtra(FileDisplayActivity.KEY_FILE_PATH, upload.getRemotePath());
@@ -857,7 +898,7 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
     }
     }
 
 
     enum Type {
     enum Type {
-        CURRENT, FINISHED, FAILED
+        CURRENT, FINISHED, FAILED, CANCELLED
     }
     }
 
 
     abstract class UploadGroup implements Refresh {
     abstract class UploadGroup implements Refresh {
@@ -901,16 +942,14 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
         }
         }
     }
     }
 
 
-    public void cancelOldErrorNotification(OCUpload upload) {
+    public void cancelOldErrorNotification(OCUpload upload){
 
 
         if (mNotificationManager == null) {
         if (mNotificationManager == null) {
             mNotificationManager = (NotificationManager) parentActivity.getSystemService(parentActivity.NOTIFICATION_SERVICE);
             mNotificationManager = (NotificationManager) parentActivity.getSystemService(parentActivity.NOTIFICATION_SERVICE);
         }
         }
 
 
-        if (upload == null) {
-            return;
-        }
-        mNotificationManager.cancel(NotificationUtils.createUploadNotificationTag(upload.getRemotePath(), upload.getLocalPath()),
+        if (upload == null) return;
+        mNotificationManager.cancel(NotificationUtils.createUploadNotificationTag(upload.getRemotePath(),upload.getLocalPath()),
                                     FileUploadWorker.NOTIFICATION_ERROR_ID);
                                     FileUploadWorker.NOTIFICATION_ERROR_ID);
 
 
     }
     }

+ 32 - 0
app/src/main/res/menu/upload_list_cancelled_options.xml

@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Nextcloud Android client application
+
+ @author Jonas Mayer
+ Copyright (C) 2024 Jonas Mayer
+ Copyright (C) 2024 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/>.
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:id="@+id/action_upload_list_cancelled_resume"
+        android:title="@string/upload_action_cancelled_resume"
+        android:icon="@drawable/ic_sync" />
+
+    <item
+        android:id="@+id/action_upload_list_cancelled_clear"
+        android:title="@string/upload_action_cancelled_clear"
+        android:icon="@drawable/ic_close" />
+</menu>

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

@@ -852,6 +852,9 @@
     <string name="upload_action_global_upload_pause">Pause all uploads</string>
     <string name="upload_action_global_upload_pause">Pause all uploads</string>
     <string name="upload_action_global_upload_resume">Resume all uploads</string>
     <string name="upload_action_global_upload_resume">Resume all uploads</string>
     <string name="dismiss_notification_description">Dismiss notification</string>
     <string name="dismiss_notification_description">Dismiss notification</string>
+    <string name="upload_action_cancelled_resume">Resume cancelled uploads</string>
+    <string name="upload_action_cancelled_clear">Clear cancelled uploads</string>
+    <string name="upload_manually_cancelled">Upload was cancelled by user</string>
     <string name="action_empty_notifications">Clear all notifications</string>
     <string name="action_empty_notifications">Clear all notifications</string>
     <string name="timeout_richDocuments">Loading is taking longer than expected</string>
     <string name="timeout_richDocuments">Loading is taking longer than expected</string>
     <string name="clear_notifications_failed">Failed to clear notifications.</string>
     <string name="clear_notifications_failed">Failed to clear notifications.</string>