mirror of
https://github.com/nextcloud/android.git
synced 2024-11-22 21:25:35 +03:00
Merge pull request #12527 from nextcloud/feature/global_upload_pause
Add global upload pause button
This commit is contained in:
commit
90f588ddad
17 changed files with 284 additions and 110 deletions
|
@ -251,6 +251,7 @@ class BackgroundJobFactory @Inject constructor(
|
|||
viewThemeUtils.get(),
|
||||
localBroadcastManager.get(),
|
||||
backgroundJobManager.get(),
|
||||
preferences,
|
||||
context,
|
||||
params
|
||||
)
|
||||
|
|
|
@ -160,7 +160,7 @@ class FileUploadHelper {
|
|||
}
|
||||
}
|
||||
|
||||
private fun cancelAndRestartUploadJob(user: User) {
|
||||
fun cancelAndRestartUploadJob(user: User) {
|
||||
backgroundJobManager.run {
|
||||
cancelFilesUploadJob(user)
|
||||
startFilesUploadJob(user)
|
||||
|
|
|
@ -32,6 +32,7 @@ import com.nextcloud.client.device.PowerManagementService
|
|||
import com.nextcloud.client.jobs.BackgroundJobManager
|
||||
import com.nextcloud.client.jobs.BackgroundJobManagerImpl
|
||||
import com.nextcloud.client.network.ConnectivityService
|
||||
import com.nextcloud.client.preferences.AppPreferences
|
||||
import com.nextcloud.model.WorkerState
|
||||
import com.nextcloud.model.WorkerStateLiveData
|
||||
import com.owncloud.android.datamodel.FileDataStorageManager
|
||||
|
@ -58,6 +59,7 @@ class FileUploadWorker(
|
|||
val viewThemeUtils: ViewThemeUtils,
|
||||
val localBroadcastManager: LocalBroadcastManager,
|
||||
private val backgroundJobManager: BackgroundJobManager,
|
||||
val preferences: AppPreferences,
|
||||
val context: Context,
|
||||
params: WorkerParameters
|
||||
) : Worker(context, params), OnDatatransferProgressListener {
|
||||
|
@ -136,11 +138,20 @@ class FileUploadWorker(
|
|||
WorkerStateLiveData.instance().setWorkState(WorkerState.Idle)
|
||||
}
|
||||
|
||||
@Suppress("ReturnCount")
|
||||
private fun retrievePagesBySortingUploadsByID(): Result {
|
||||
val accountName = inputData.getString(ACCOUNT) ?: return Result.failure()
|
||||
var currentPage = uploadsStorageManager.getCurrentAndPendingUploadsForAccountPageAscById(-1, accountName)
|
||||
|
||||
while (currentPage.isNotEmpty() && !isStopped) {
|
||||
if (preferences.isGlobalUploadPaused) {
|
||||
Log_OC.d(TAG, "Upload is paused, skip uploading files!")
|
||||
notificationManager.notifyPaused(
|
||||
intents.notificationStartIntent(null)
|
||||
)
|
||||
return Result.success()
|
||||
}
|
||||
|
||||
Log_OC.d(TAG, "Handling ${currentPage.size} uploads for account $accountName")
|
||||
val lastId = currentPage.last().uploadId
|
||||
uploadFiles(currentPage, accountName)
|
||||
|
|
|
@ -97,10 +97,10 @@ class FileUploaderIntents(private val context: Context) {
|
|||
)
|
||||
}
|
||||
|
||||
fun notificationStartIntent(operation: UploadFileOperation): PendingIntent {
|
||||
fun notificationStartIntent(operation: UploadFileOperation?): PendingIntent {
|
||||
val intent = UploadListActivity.createIntent(
|
||||
operation.file,
|
||||
operation.user,
|
||||
operation?.file,
|
||||
operation?.user,
|
||||
Intent.FLAG_ACTIVITY_CLEAR_TOP,
|
||||
context
|
||||
)
|
||||
|
|
|
@ -35,17 +35,14 @@ import com.owncloud.android.operations.UploadFileOperation
|
|||
import com.owncloud.android.ui.notifications.NotificationUtils
|
||||
import com.owncloud.android.utils.theme.ViewThemeUtils
|
||||
|
||||
class UploadNotificationManager(private val context: Context, private val viewThemeUtils: ViewThemeUtils) {
|
||||
class UploadNotificationManager(private val context: Context, viewThemeUtils: ViewThemeUtils) {
|
||||
companion object {
|
||||
private const val ID = 411
|
||||
}
|
||||
|
||||
private var notification: Notification? = null
|
||||
private var notificationBuilder: NotificationCompat.Builder
|
||||
private val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
|
||||
init {
|
||||
notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils).apply {
|
||||
private var notificationBuilder: NotificationCompat.Builder =
|
||||
NotificationUtils.newNotificationBuilder(context, viewThemeUtils).apply {
|
||||
setContentTitle(context.getString(R.string.foreground_service_upload))
|
||||
setSmallIcon(R.drawable.notification_icon)
|
||||
setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.notification_icon))
|
||||
|
@ -54,18 +51,16 @@ class UploadNotificationManager(private val context: Context, private val viewTh
|
|||
setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_UPLOAD)
|
||||
}
|
||||
}
|
||||
private val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
|
||||
init {
|
||||
notification = notificationBuilder.build()
|
||||
}
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
fun prepareForStart(upload: UploadFileOperation, pendingIntent: PendingIntent, startIntent: PendingIntent) {
|
||||
notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils).apply {
|
||||
setSmallIcon(R.drawable.notification_icon)
|
||||
setOngoing(true)
|
||||
setTicker(context.getString(R.string.foreground_service_upload))
|
||||
notificationBuilder.run {
|
||||
setContentTitle(context.getString(R.string.uploader_upload_in_progress_ticker))
|
||||
setProgress(100, 0, false)
|
||||
setContentText(
|
||||
String.format(
|
||||
context.getString(R.string.uploader_upload_in_progress),
|
||||
|
@ -73,6 +68,9 @@ class UploadNotificationManager(private val context: Context, private val viewTh
|
|||
upload.fileName
|
||||
)
|
||||
)
|
||||
setTicker(context.getString(R.string.foreground_service_upload))
|
||||
setProgress(100, 0, false)
|
||||
setOngoing(true)
|
||||
clearActions()
|
||||
|
||||
addAction(
|
||||
|
@ -81,10 +79,6 @@ class UploadNotificationManager(private val context: Context, private val viewTh
|
|||
pendingIntent
|
||||
)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_UPLOAD)
|
||||
}
|
||||
|
||||
setContentIntent(startIntent)
|
||||
}
|
||||
|
||||
|
@ -192,4 +186,18 @@ class UploadNotificationManager(private val context: Context, private val viewTh
|
|||
fun dismissWorkerNotifications() {
|
||||
notificationManager.cancel(ID)
|
||||
}
|
||||
|
||||
fun notifyPaused(intent: PendingIntent) {
|
||||
notificationBuilder.apply {
|
||||
setContentTitle(context.getString(R.string.upload_global_pause_title))
|
||||
setTicker(context.getString(R.string.upload_global_pause_title))
|
||||
setOngoing(true)
|
||||
setAutoCancel(false)
|
||||
setProgress(0, 0, false)
|
||||
clearActions()
|
||||
setContentIntent(intent)
|
||||
}
|
||||
|
||||
showNotification()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -387,6 +387,10 @@ public interface AppPreferences {
|
|||
|
||||
void setCalendarLastBackup(long timestamp);
|
||||
|
||||
boolean isGlobalUploadPaused();
|
||||
|
||||
void setGlobalUploadPaused(boolean globalPausedState);
|
||||
|
||||
void setPdfZoomTipShownCount(int count);
|
||||
|
||||
int getPdfZoomTipShownCount();
|
||||
|
|
|
@ -107,6 +107,8 @@ public final class AppPreferencesImpl implements AppPreferences {
|
|||
private static final String PREF__CALENDAR_AUTOMATIC_BACKUP = "calendar_automatic_backup";
|
||||
private static final String PREF__CALENDAR_LAST_BACKUP = "calendar_last_backup";
|
||||
|
||||
private static final String PREF__GLOBAL_PAUSE_STATE = "global_pause_state";
|
||||
|
||||
private static final String PREF__PDF_ZOOM_TIP_SHOWN = "pdf_zoom_tip_shown";
|
||||
private static final String PREF__MEDIA_FOLDER_LAST_PATH = "media_folder_last_path";
|
||||
|
||||
|
@ -741,6 +743,16 @@ public final class AppPreferencesImpl implements AppPreferences {
|
|||
preferences.edit().putLong(PREF__CALENDAR_LAST_BACKUP, timestamp).apply();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGlobalUploadPaused() {
|
||||
return preferences.getBoolean(PREF__GLOBAL_PAUSE_STATE,false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGlobalUploadPaused(boolean globalPausedState) {
|
||||
preferences.edit().putBoolean(PREF__GLOBAL_PAUSE_STATE, globalPausedState).apply();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPdfZoomTipShownCount(int count) {
|
||||
preferences.edit().putInt(PREF__PDF_ZOOM_TIP_SHOWN, count).apply();
|
||||
|
|
|
@ -1155,6 +1155,10 @@ public abstract class DrawerActivity extends ToolbarActivity
|
|||
return true;
|
||||
}
|
||||
|
||||
public AppPreferences getAppPreferences(){
|
||||
return preferences;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
package com.owncloud.android.ui.activity;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
@ -49,7 +50,6 @@ import com.owncloud.android.R;
|
|||
import com.owncloud.android.databinding.UploadListLayoutBinding;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.datamodel.UploadsStorageManager;
|
||||
import com.owncloud.android.db.OCUpload;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperation;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
|
@ -65,11 +65,11 @@ import javax.inject.Inject;
|
|||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
|
||||
/**
|
||||
* Activity listing pending, active, and completed uploads. User can delete
|
||||
* completed uploads from view. Content of this list of coming from
|
||||
* {@link UploadsStorageManager}.
|
||||
* Activity listing pending, active, and completed uploads. User can delete completed uploads from view. Content of this
|
||||
* list of coming from {@link UploadsStorageManager}.
|
||||
*/
|
||||
public class UploadListActivity extends FileActivity {
|
||||
|
||||
|
@ -210,13 +210,17 @@ public class UploadListActivity extends FileActivity {
|
|||
private void refresh() {
|
||||
backgroundJobManager.startImmediateFilesSyncJob(false, true);
|
||||
|
||||
if(uploadsStorageManager.getFailedUploads().length > 0){
|
||||
new Thread(() -> FileUploadHelper.Companion.instance().retryFailedUploads(
|
||||
uploadsStorageManager,
|
||||
connectivityService,
|
||||
userAccountManager,
|
||||
powerManagementService))
|
||||
.start();
|
||||
if (uploadsStorageManager.getFailedUploads().length > 0) {
|
||||
new Thread(() -> {
|
||||
FileUploadHelper.Companion.instance().retryFailedUploads(
|
||||
uploadsStorageManager,
|
||||
connectivityService,
|
||||
accountManager,
|
||||
powerManagementService);
|
||||
this.runOnUiThread(() -> {
|
||||
uploadListAdapter.loadUploadItemsFromDb();
|
||||
});
|
||||
}).start();
|
||||
DisplayUtils.showSnackMessage(this, R.string.uploader_local_files_uploaded);
|
||||
}
|
||||
|
||||
|
@ -265,13 +269,47 @@ public class UploadListActivity extends FileActivity {
|
|||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.activity_upload_list, menu);
|
||||
|
||||
updateGlobalPauseIcon(menu.getItem(0));
|
||||
return true;
|
||||
}
|
||||
|
||||
@SuppressFBWarnings("RV_RETURN_VALUE_IGNORED_NO_SIDE_EFFECT")
|
||||
private void updateGlobalPauseIcon(MenuItem pauseMenuItem) {
|
||||
if (pauseMenuItem.getItemId() != R.id.action_toggle_global_pause) {
|
||||
return;
|
||||
}
|
||||
|
||||
int iconId;
|
||||
String title;
|
||||
if (preferences.isGlobalUploadPaused()) {
|
||||
iconId = R.drawable.ic_play;
|
||||
title = getString(R.string.upload_action_global_upload_resume);
|
||||
} else {
|
||||
iconId = R.drawable.ic_pause;
|
||||
title = getString(R.string.upload_action_global_upload_pause);
|
||||
}
|
||||
|
||||
pauseMenuItem.setIcon(iconId);
|
||||
pauseMenuItem.setTitle(title);
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
private void toggleGlobalPause(MenuItem pauseMenuItem) {
|
||||
preferences.setGlobalUploadPaused(!preferences.isGlobalUploadPaused());
|
||||
updateGlobalPauseIcon(pauseMenuItem);
|
||||
|
||||
for (User user : accountManager.getAllUsers()) {
|
||||
if (user != null) {
|
||||
FileUploadHelper.Companion.instance().cancelAndRestartUploadJob(user);
|
||||
}
|
||||
}
|
||||
|
||||
uploadListAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
boolean retval = true;
|
||||
|
||||
int itemId = item.getItemId();
|
||||
|
||||
if (itemId == android.R.id.home) {
|
||||
|
@ -280,17 +318,13 @@ public class UploadListActivity extends FileActivity {
|
|||
} else {
|
||||
openDrawer();
|
||||
}
|
||||
} else if (itemId == R.id.action_clear_failed_uploads) {
|
||||
for (OCUpload upload : uploadsStorageManager.getFailedButNotDelayedUploadsForCurrentAccount()){
|
||||
uploadListAdapter.cancelOldErrorNotification(upload);
|
||||
}
|
||||
uploadsStorageManager.clearFailedButNotDelayedUploads();
|
||||
uploadListAdapter.loadUploadItemsFromDb();
|
||||
} else if (itemId == R.id.action_toggle_global_pause) {
|
||||
toggleGlobalPause(item);
|
||||
} else {
|
||||
retval = super.onOptionsItemSelected(item);
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
return retval;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -29,7 +29,6 @@ import android.content.ActivityNotFoundException;
|
|||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Typeface;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.text.format.DateUtils;
|
||||
|
@ -123,31 +122,57 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
|
|||
|
||||
switch (group.type) {
|
||||
case CURRENT, FINISHED -> headerViewHolder.binding.uploadListAction.setImageResource(R.drawable.ic_close);
|
||||
case FAILED -> headerViewHolder.binding.uploadListAction.setImageResource(R.drawable.ic_sync);
|
||||
case FAILED -> headerViewHolder.binding.uploadListAction.setImageResource(R.drawable.ic_dots_vertical);
|
||||
}
|
||||
|
||||
headerViewHolder.binding.uploadListAction.setOnClickListener(v -> {
|
||||
switch (group.type) {
|
||||
case CURRENT -> {
|
||||
// cancel all current uploads
|
||||
for (OCUpload upload : group.getItems()) {
|
||||
uploadHelper.cancelFileUpload(upload.getRemotePath(), upload.getAccountName());
|
||||
}
|
||||
loadUploadItemsFromDb();
|
||||
}
|
||||
case FINISHED -> uploadsStorageManager.clearSuccessfulUploads();
|
||||
case FAILED -> new Thread(() -> FileUploadHelper.Companion.instance().retryFailedUploads(
|
||||
uploadsStorageManager,
|
||||
connectivityService,
|
||||
accountManager,
|
||||
powerManagementService)).start();
|
||||
default -> {
|
||||
case FINISHED -> {
|
||||
// clear successfully uploaded section
|
||||
uploadsStorageManager.clearSuccessfulUploads();
|
||||
loadUploadItemsFromDb();
|
||||
}
|
||||
case FAILED -> {
|
||||
// show popup with option clear or retry filed uploads
|
||||
createFailedPopupMenu(headerViewHolder);
|
||||
}
|
||||
// do nothing
|
||||
}
|
||||
|
||||
loadUploadItemsFromDb();
|
||||
});
|
||||
}
|
||||
|
||||
private void createFailedPopupMenu(HeaderViewHolder headerViewHolder) {
|
||||
PopupMenu failedPopup = new PopupMenu(MainApp.getAppContext(), headerViewHolder.binding.uploadListAction);
|
||||
failedPopup.inflate(R.menu.upload_list_failed_options);
|
||||
failedPopup.setOnMenuItemClickListener(i -> {
|
||||
int itemId = i.getItemId();
|
||||
|
||||
if (itemId == R.id.action_upload_list_failed_clear) {
|
||||
uploadsStorageManager.clearFailedButNotDelayedUploads();
|
||||
loadUploadItemsFromDb();
|
||||
} else {
|
||||
|
||||
new Thread(() -> {
|
||||
FileUploadHelper.Companion.instance().retryFailedUploads(
|
||||
uploadsStorageManager,
|
||||
connectivityService,
|
||||
accountManager,
|
||||
powerManagementService);
|
||||
parentActivity.runOnUiThread(this::loadUploadItemsFromDb);
|
||||
}).start();
|
||||
|
||||
}
|
||||
return true;
|
||||
});
|
||||
failedPopup.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindFooterViewHolder(SectionedViewHolder holder, int section) {
|
||||
// not needed
|
||||
|
@ -228,7 +253,7 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
|
|||
// file size
|
||||
if (item.getFileSize() != 0) {
|
||||
itemViewHolder.binding.uploadFileSize.setText(String.format("%s, ",
|
||||
DisplayUtils.bytesToHumanReadable(item.getFileSize())));
|
||||
DisplayUtils.bytesToHumanReadable(item.getFileSize())));
|
||||
} else {
|
||||
itemViewHolder.binding.uploadFileSize.setText("");
|
||||
}
|
||||
|
@ -260,7 +285,6 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
|
|||
itemViewHolder.binding.uploadRemotePath.setVisibility(View.VISIBLE);
|
||||
itemViewHolder.binding.uploadFileSize.setVisibility(View.VISIBLE);
|
||||
itemViewHolder.binding.uploadStatus.setVisibility(View.VISIBLE);
|
||||
itemViewHolder.binding.uploadStatus.setTypeface(null, Typeface.NORMAL);
|
||||
itemViewHolder.binding.uploadProgressBar.setVisibility(View.GONE);
|
||||
|
||||
// Update information depending of upload details
|
||||
|
@ -304,9 +328,8 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
|
|||
}
|
||||
|
||||
// show status if same file conflict or local file deleted
|
||||
if (item.getUploadStatus() == UploadStatus.UPLOAD_SUCCEEDED && item.getLastResult() != UploadResult.UPLOADED){
|
||||
if (item.getUploadStatus() == UploadStatus.UPLOAD_SUCCEEDED && item.getLastResult() != UploadResult.UPLOADED) {
|
||||
itemViewHolder.binding.uploadStatus.setVisibility(View.VISIBLE);
|
||||
itemViewHolder.binding.uploadStatus.setTypeface(null, Typeface.BOLD);
|
||||
itemViewHolder.binding.uploadDate.setVisibility(View.GONE);
|
||||
itemViewHolder.binding.uploadFileSize.setVisibility(View.GONE);
|
||||
}
|
||||
|
@ -373,16 +396,16 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
|
|||
DisplayUtils.showSnackMessage(
|
||||
v.getRootView().findViewById(android.R.id.content),
|
||||
R.string.local_file_not_found_message
|
||||
);
|
||||
);
|
||||
}
|
||||
});
|
||||
} else if (item.getUploadStatus() == UploadStatus.UPLOAD_SUCCEEDED){
|
||||
} else if (item.getUploadStatus() == UploadStatus.UPLOAD_SUCCEEDED) {
|
||||
itemViewHolder.binding.uploadListItemLayout.setOnClickListener(v -> onUploadedItemClick(item));
|
||||
}
|
||||
|
||||
|
||||
// click on thumbnail to open locally
|
||||
if (item.getUploadStatus() != UploadStatus.UPLOAD_SUCCEEDED){
|
||||
if (item.getUploadStatus() != UploadStatus.UPLOAD_SUCCEEDED) {
|
||||
itemViewHolder.binding.thumbnail.setOnClickListener(v -> onUploadingItemClick(item));
|
||||
}
|
||||
|
||||
|
@ -395,17 +418,17 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
|
|||
fakeFileToCheatThumbnailsCacheManagerInterface.setMimeType(item.getMimeType());
|
||||
|
||||
boolean allowedToCreateNewThumbnail = ThumbnailsCacheManager.cancelPotentialThumbnailWork(
|
||||
fakeFileToCheatThumbnailsCacheManagerInterface, itemViewHolder.binding.thumbnail
|
||||
);
|
||||
fakeFileToCheatThumbnailsCacheManagerInterface, itemViewHolder.binding.thumbnail
|
||||
);
|
||||
|
||||
// TODO this code is duplicated; refactor to a common place
|
||||
if (MimeTypeUtil.isImage(fakeFileToCheatThumbnailsCacheManagerInterface)
|
||||
&& fakeFileToCheatThumbnailsCacheManagerInterface.getRemoteId() != null &&
|
||||
item.getUploadStatus() == UploadStatus.UPLOAD_SUCCEEDED) {
|
||||
&& fakeFileToCheatThumbnailsCacheManagerInterface.getRemoteId() != null &&
|
||||
item.getUploadStatus() == UploadStatus.UPLOAD_SUCCEEDED) {
|
||||
// Thumbnail in Cache?
|
||||
Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache(
|
||||
String.valueOf(fakeFileToCheatThumbnailsCacheManagerInterface.getRemoteId())
|
||||
);
|
||||
String.valueOf(fakeFileToCheatThumbnailsCacheManagerInterface.getRemoteId())
|
||||
);
|
||||
if (thumbnail != null && !fakeFileToCheatThumbnailsCacheManagerInterface.isUpdateThumbnailNeeded()) {
|
||||
itemViewHolder.binding.thumbnail.setImageBitmap(thumbnail);
|
||||
} else {
|
||||
|
@ -413,11 +436,11 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
|
|||
Optional<User> user = parentActivity.getUser();
|
||||
if (allowedToCreateNewThumbnail && user.isPresent()) {
|
||||
final ThumbnailsCacheManager.ThumbnailGenerationTask task =
|
||||
new ThumbnailsCacheManager.ThumbnailGenerationTask(
|
||||
itemViewHolder.binding.thumbnail,
|
||||
parentActivity.getStorageManager(),
|
||||
user.get()
|
||||
);
|
||||
new ThumbnailsCacheManager.ThumbnailGenerationTask(
|
||||
itemViewHolder.binding.thumbnail,
|
||||
parentActivity.getStorageManager(),
|
||||
user.get()
|
||||
);
|
||||
if (thumbnail == null) {
|
||||
if (MimeTypeUtil.isVideo(fakeFileToCheatThumbnailsCacheManagerInterface)) {
|
||||
thumbnail = ThumbnailsCacheManager.mDefaultVideo;
|
||||
|
@ -426,20 +449,20 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
|
|||
}
|
||||
}
|
||||
final ThumbnailsCacheManager.AsyncThumbnailDrawable asyncDrawable =
|
||||
new ThumbnailsCacheManager.AsyncThumbnailDrawable(
|
||||
parentActivity.getResources(),
|
||||
thumbnail,
|
||||
task
|
||||
);
|
||||
new ThumbnailsCacheManager.AsyncThumbnailDrawable(
|
||||
parentActivity.getResources(),
|
||||
thumbnail,
|
||||
task
|
||||
);
|
||||
itemViewHolder.binding.thumbnail.setImageDrawable(asyncDrawable);
|
||||
task.execute(new ThumbnailsCacheManager.ThumbnailGenerationTaskObject(
|
||||
fakeFileToCheatThumbnailsCacheManagerInterface, null));
|
||||
fakeFileToCheatThumbnailsCacheManagerInterface, null));
|
||||
}
|
||||
}
|
||||
|
||||
if ("image/png".equals(item.getMimeType())) {
|
||||
itemViewHolder.binding.thumbnail.setBackgroundColor(parentActivity.getResources()
|
||||
.getColor(R.color.bg_default));
|
||||
.getColor(R.color.bg_default));
|
||||
}
|
||||
|
||||
|
||||
|
@ -447,14 +470,14 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
|
|||
File file = new File(item.getLocalPath());
|
||||
// Thumbnail in Cache?
|
||||
Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache(
|
||||
String.valueOf(file.hashCode()));
|
||||
String.valueOf(file.hashCode()));
|
||||
if (thumbnail != null) {
|
||||
itemViewHolder.binding.thumbnail.setImageBitmap(thumbnail);
|
||||
} else {
|
||||
// generate new Thumbnail
|
||||
if (allowedToCreateNewThumbnail) {
|
||||
final ThumbnailsCacheManager.ThumbnailGenerationTask task =
|
||||
new ThumbnailsCacheManager.ThumbnailGenerationTask(itemViewHolder.binding.thumbnail);
|
||||
new ThumbnailsCacheManager.ThumbnailGenerationTask(itemViewHolder.binding.thumbnail);
|
||||
|
||||
if (MimeTypeUtil.isVideo(file)) {
|
||||
thumbnail = ThumbnailsCacheManager.mDefaultVideo;
|
||||
|
@ -474,7 +497,7 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
|
|||
|
||||
if ("image/png".equalsIgnoreCase(item.getMimeType())) {
|
||||
itemViewHolder.binding.thumbnail.setBackgroundColor(parentActivity.getResources()
|
||||
.getColor(R.color.bg_default));
|
||||
.getColor(R.color.bg_default));
|
||||
}
|
||||
} else {
|
||||
if (optionalUser.isPresent()) {
|
||||
|
@ -605,8 +628,7 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets the status text to show to the user according to the status and last result of the
|
||||
* the given upload.
|
||||
* Gets the status text to show to the user according to the status and last result of the the given upload.
|
||||
*
|
||||
* @param upload Upload to describe.
|
||||
* @return Text describing the status of the given upload.
|
||||
|
@ -614,30 +636,27 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
|
|||
private String getStatusText(OCUpload upload) {
|
||||
String status;
|
||||
switch (upload.getUploadStatus()) {
|
||||
case UPLOAD_IN_PROGRESS:
|
||||
case UPLOAD_IN_PROGRESS -> {
|
||||
status = parentActivity.getString(R.string.uploads_view_later_waiting_to_upload);
|
||||
if (uploadHelper.isUploadingNow(upload)) {
|
||||
// really uploading, bind the progress bar to listen for progress updates
|
||||
status = parentActivity.getString(R.string.uploader_upload_in_progress_ticker);
|
||||
}
|
||||
break;
|
||||
|
||||
case UPLOAD_SUCCEEDED:
|
||||
if (upload.getLastResult() == UploadResult.SAME_FILE_CONFLICT){
|
||||
if (parentActivity.getAppPreferences().isGlobalUploadPaused()) {
|
||||
status = parentActivity.getString(R.string.upload_global_pause_title);
|
||||
}
|
||||
}
|
||||
case UPLOAD_SUCCEEDED -> {
|
||||
if (upload.getLastResult() == UploadResult.SAME_FILE_CONFLICT) {
|
||||
status = parentActivity.getString(R.string.uploads_view_upload_status_succeeded_same_file);
|
||||
}else if (upload.getLastResult() == UploadResult.FILE_NOT_FOUND) {
|
||||
} else if (upload.getLastResult() == UploadResult.FILE_NOT_FOUND) {
|
||||
status = getUploadFailedStatusText(upload.getLastResult());
|
||||
} else {
|
||||
status = parentActivity.getString(R.string.uploads_view_upload_status_succeeded);
|
||||
}
|
||||
break;
|
||||
|
||||
case UPLOAD_FAILED:
|
||||
status = getUploadFailedStatusText(upload.getLastResult());
|
||||
break;
|
||||
|
||||
default:
|
||||
status = "Uncontrolled status: " + upload.getUploadStatus();
|
||||
}
|
||||
case UPLOAD_FAILED -> status = getUploadFailedStatusText(upload.getLastResult());
|
||||
default -> status = "Uncontrolled status: " + upload.getUploadStatus();
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
@ -690,8 +709,8 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
|
|||
case SSL_RECOVERABLE_PEER_UNVERIFIED:
|
||||
status =
|
||||
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;
|
||||
case UNKNOWN:
|
||||
status = parentActivity.getString(R.string.uploads_view_upload_status_unknown_fail);
|
||||
|
@ -701,7 +720,7 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
|
|||
break;
|
||||
case DELAYED_IN_POWER_SAVE_MODE:
|
||||
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;
|
||||
case VIRUS_DETECTED:
|
||||
status = parentActivity.getString(R.string.uploads_view_upload_status_virus_detected);
|
||||
|
@ -776,17 +795,17 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
|
|||
*/
|
||||
private void onUploadedItemClick(OCUpload upload) {
|
||||
final OCFile file = parentActivity.getStorageManager().getFileByEncryptedRemotePath(upload.getRemotePath());
|
||||
if (file == null){
|
||||
if (file == null) {
|
||||
DisplayUtils.showSnackMessage(parentActivity, R.string.error_retrieving_file);
|
||||
Log_OC.i(TAG, "Could not find uploaded file on remote.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (PreviewImageFragment.canBePreviewed(file)){
|
||||
if (PreviewImageFragment.canBePreviewed(file)) {
|
||||
//show image preview and stay in uploads tab
|
||||
Intent intent = FileDisplayActivity.openFileIntent(parentActivity, parentActivity.getUser().get(), file);
|
||||
parentActivity.startActivity(intent);
|
||||
}else{
|
||||
} else {
|
||||
Intent intent = new Intent(parentActivity, FileDisplayActivity.class);
|
||||
intent.setAction(Intent.ACTION_VIEW);
|
||||
intent.putExtra(FileDisplayActivity.KEY_FILE_PATH, upload.getRemotePath());
|
||||
|
@ -882,14 +901,16 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
|
|||
}
|
||||
}
|
||||
|
||||
public void cancelOldErrorNotification(OCUpload upload){
|
||||
public void cancelOldErrorNotification(OCUpload upload) {
|
||||
|
||||
if (mNotificationManager == null) {
|
||||
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);
|
||||
|
||||
}
|
||||
|
|
9
app/src/main/res/drawable/ic_pause.xml
Normal file
9
app/src/main/res/drawable/ic_pause.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960">
|
||||
<path
|
||||
android:fillColor="@color/foreground_highlight"
|
||||
android:pathData="M560,760v-560h160v560L560,760ZM240,760v-560h160v560L240,760Z"/>
|
||||
</vector>
|
30
app/src/main/res/drawable/ic_play.xml
Normal file
30
app/src/main/res/drawable/ic_play.xml
Normal file
|
@ -0,0 +1,30 @@
|
|||
<!--
|
||||
~ 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/>.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960">
|
||||
<path
|
||||
android:fillColor="@color/foreground_highlight"
|
||||
android:pathData="M320,760v-560l440,280 -440,280Z"/>
|
||||
</vector>
|
|
@ -16,13 +16,16 @@
|
|||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<group
|
||||
android:id="@+id/upload_list_actions"
|
||||
android:checkableBehavior="none">
|
||||
|
||||
<item
|
||||
android:id="@+id/action_clear_failed_uploads"
|
||||
android:title="@string/action_clear_failed_uploads" />
|
||||
android:id="@+id/action_toggle_global_pause"
|
||||
android:icon="@android:drawable/ic_media_pause"
|
||||
android:title="@string/upload_action_global_upload_pause"
|
||||
app:showAsAction="always" />
|
||||
</group>
|
||||
</menu>
|
||||
|
|
32
app/src/main/res/menu/upload_list_failed_options.xml
Normal file
32
app/src/main/res/menu/upload_list_failed_options.xml
Normal file
|
@ -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_failed_retry"
|
||||
android:icon="@drawable/ic_sync"
|
||||
android:title="@string/upload_action_failed_retry" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_upload_list_failed_clear"
|
||||
android:title="@string/upload_action_failed_clear"
|
||||
android:icon="@drawable/ic_close" />
|
||||
</menu>
|
|
@ -33,6 +33,7 @@
|
|||
<color name="grey_200">#818181</color>
|
||||
<color name="nc_grey">#222222</color>
|
||||
<color name="icon_on_nc_grey">#ffffff</color>
|
||||
<color name="foreground_highlight">#EAE0E5</color>
|
||||
|
||||
<!-- Multiselect backgrounds -->
|
||||
<color name="action_mode_background">@color/appbar</color>
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
<color name="secondary_button_text_color">#000000</color>
|
||||
<color name="nc_grey">#ededed</color>
|
||||
<color name="icon_on_nc_grey">#000000</color>
|
||||
<color name="foreground_highlight">#1D1B1E</color>
|
||||
|
||||
<color name="process_dialog_background">#ffffff</color>
|
||||
<color name="indicator_dot_selected">#ffffff</color>
|
||||
|
|
|
@ -522,8 +522,6 @@
|
|||
<string name="share_room_clarification">%1$s (conversation)</string>
|
||||
<string name="share_known_remote_on_clarification">on %1$s</string>
|
||||
|
||||
<string name="action_clear_failed_uploads">Clear failed uploads</string>
|
||||
|
||||
<string name="action_switch_grid_view">Grid view</string>
|
||||
<string name="action_switch_list_view">List view</string>
|
||||
|
||||
|
@ -845,9 +843,14 @@
|
|||
<string name="upload_sync_conflict">Sync conflict, please resolve manually</string>
|
||||
<string name="upload_cannot_create_file">Cannot create local file</string>
|
||||
<string name="upload_local_storage_not_copied">File could not be copied to local storage</string>
|
||||
<string name="upload_global_pause_title">All uploads are paused</string>
|
||||
<string name="upload_quota_exceeded">Storage quota exceeded</string>
|
||||
<string name="host_not_available">Server not available</string>
|
||||
<string name="delete_entries">Delete entries</string>
|
||||
<string name="upload_action_failed_retry">Retry failed uploads</string>
|
||||
<string name="upload_action_failed_clear">Clear failed 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="dismiss_notification_description">Dismiss notification</string>
|
||||
<string name="action_empty_notifications">Clear all notifications</string>
|
||||
<string name="timeout_richDocuments">Loading is taking longer than expected</string>
|
||||
|
|
Loading…
Reference in a new issue