mirror of https://github.com/nextcloud/android
373 lines
13 KiB
Java
Executable File
373 lines
13 KiB
Java
Executable File
/*
|
|
* Nextcloud Android client application
|
|
*
|
|
* @author Tobias Kaminsky
|
|
* @author Chris Narkiewicz
|
|
* Copyright (C) 2018 Tobias Kaminsky
|
|
* Copyright (C) 2018 Nextcloud
|
|
* Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
|
|
*
|
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
|
*/
|
|
|
|
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;
|
|
import android.content.IntentFilter;
|
|
import android.os.Bundle;
|
|
import android.view.Menu;
|
|
import android.view.MenuInflater;
|
|
import android.view.MenuItem;
|
|
import android.view.View;
|
|
|
|
import com.nextcloud.client.account.User;
|
|
import com.nextcloud.client.account.UserAccountManager;
|
|
import com.nextcloud.client.core.Clock;
|
|
import com.nextcloud.client.device.PowerManagementService;
|
|
import com.nextcloud.client.jobs.BackgroundJobManager;
|
|
import com.nextcloud.client.jobs.upload.FileUploadHelper;
|
|
import com.nextcloud.client.jobs.upload.FileUploadWorker;
|
|
import com.nextcloud.client.network.ConnectivityService;
|
|
import com.nextcloud.client.utils.Throttler;
|
|
import com.nextcloud.model.WorkerState;
|
|
import com.nextcloud.model.WorkerStateLiveData;
|
|
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.lib.common.operations.RemoteOperation;
|
|
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
|
import com.owncloud.android.lib.common.utils.Log_OC;
|
|
import com.owncloud.android.operations.CheckCurrentCredentialsOperation;
|
|
import com.owncloud.android.ui.adapter.UploadListAdapter;
|
|
import com.owncloud.android.ui.decoration.MediaGridItemDecoration;
|
|
import com.owncloud.android.utils.DisplayUtils;
|
|
import com.owncloud.android.utils.FilesSyncHelper;
|
|
import com.owncloud.android.utils.theme.ViewThemeUtils;
|
|
|
|
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}.
|
|
*/
|
|
public class UploadListActivity extends FileActivity {
|
|
|
|
private static final String TAG = UploadListActivity.class.getSimpleName();
|
|
|
|
private UploadMessagesReceiver uploadMessagesReceiver;
|
|
|
|
private UploadListAdapter uploadListAdapter;
|
|
|
|
public SwipeRefreshLayout swipeListRefreshLayout;
|
|
|
|
@Inject
|
|
UserAccountManager userAccountManager;
|
|
|
|
@Inject
|
|
UploadsStorageManager uploadsStorageManager;
|
|
|
|
@Inject
|
|
ConnectivityService connectivityService;
|
|
|
|
@Inject
|
|
PowerManagementService powerManagementService;
|
|
|
|
@Inject
|
|
Clock clock;
|
|
|
|
@Inject
|
|
BackgroundJobManager backgroundJobManager;
|
|
|
|
@Inject
|
|
LocalBroadcastManager localBroadcastManager;
|
|
|
|
@Inject
|
|
ViewThemeUtils viewThemeUtils;
|
|
|
|
@Inject Throttler throttler;
|
|
|
|
private UploadListLayoutBinding binding;
|
|
|
|
public static Intent createIntent(OCFile file, User user, Integer flag, Context context) {
|
|
Intent intent = new Intent(context, UploadListActivity.class);
|
|
if (flag != null) {
|
|
intent.setFlags(intent.getFlags() | flag);
|
|
}
|
|
intent.putExtra(ConflictsResolveActivity.EXTRA_FILE, file);
|
|
intent.putExtra(ConflictsResolveActivity.EXTRA_USER, user);
|
|
|
|
return intent;
|
|
}
|
|
|
|
@Override
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
super.onCreate(savedInstanceState);
|
|
|
|
throttler.setIntervalMillis(1000);
|
|
|
|
binding = UploadListLayoutBinding.inflate(getLayoutInflater());
|
|
setContentView(binding.getRoot());
|
|
|
|
swipeListRefreshLayout = binding.swipeContainingList;
|
|
|
|
// this activity has no file really bound, it's for multiple accounts at the same time; should no inherit
|
|
// from FileActivity; moreover, some behaviours inherited from FileActivity should be delegated to Fragments;
|
|
// but that's other story
|
|
setFile(null);
|
|
|
|
// setup toolbar
|
|
setupToolbar();
|
|
|
|
updateActionBarTitleAndHomeButtonByString(getString(R.string.uploads_view_title));
|
|
|
|
// setup drawer
|
|
setupDrawer(R.id.nav_uploads);
|
|
|
|
setupContent();
|
|
observeWorkerState();
|
|
}
|
|
|
|
private void observeWorkerState() {
|
|
WorkerStateLiveData.Companion.instance().observe(this, state -> {
|
|
if (state instanceof WorkerState.Upload) {
|
|
Log_OC.d(TAG, "Upload worker started");
|
|
handleUploadWorkerState();
|
|
}
|
|
});
|
|
}
|
|
|
|
private void handleUploadWorkerState() {
|
|
uploadListAdapter.loadUploadItemsFromDb();
|
|
}
|
|
|
|
private void setupContent() {
|
|
binding.list.setEmptyView(binding.emptyList.getRoot());
|
|
binding.emptyList.getRoot().setVisibility(View.GONE);
|
|
binding.emptyList.emptyListIcon.setImageResource(R.drawable.uploads);
|
|
binding.emptyList.emptyListIcon.getDrawable().mutate();
|
|
binding.emptyList.emptyListIcon.setAlpha(0.5f);
|
|
binding.emptyList.emptyListIcon.setVisibility(View.VISIBLE);
|
|
binding.emptyList.emptyListViewHeadline.setText(getString(R.string.upload_list_empty_headline));
|
|
binding.emptyList.emptyListViewText.setText(getString(R.string.upload_list_empty_text_auto_upload));
|
|
binding.emptyList.emptyListViewText.setVisibility(View.VISIBLE);
|
|
|
|
uploadListAdapter = new UploadListAdapter(this,
|
|
uploadsStorageManager,
|
|
getStorageManager(),
|
|
userAccountManager,
|
|
connectivityService,
|
|
powerManagementService,
|
|
clock,
|
|
viewThemeUtils);
|
|
|
|
final GridLayoutManager lm = new GridLayoutManager(this, 1);
|
|
uploadListAdapter.setLayoutManager(lm);
|
|
|
|
int spacing = getResources().getDimensionPixelSize(R.dimen.media_grid_spacing);
|
|
binding.list.addItemDecoration(new MediaGridItemDecoration(spacing));
|
|
binding.list.setLayoutManager(lm);
|
|
binding.list.setAdapter(uploadListAdapter);
|
|
|
|
viewThemeUtils.androidx.themeSwipeRefreshLayout(swipeListRefreshLayout);
|
|
swipeListRefreshLayout.setOnRefreshListener(this::refresh);
|
|
|
|
loadItems();
|
|
uploadListAdapter.loadUploadItemsFromDb();
|
|
}
|
|
|
|
private void loadItems() {
|
|
uploadListAdapter.loadUploadItemsFromDb();
|
|
|
|
if (uploadListAdapter.getItemCount() > 0) {
|
|
return;
|
|
}
|
|
|
|
swipeListRefreshLayout.setVisibility(View.VISIBLE);
|
|
swipeListRefreshLayout.setRefreshing(false);
|
|
}
|
|
|
|
private void refresh() {
|
|
backgroundJobManager.startImmediateFilesSyncJob(true,new String[]{});
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
// update UI
|
|
uploadListAdapter.loadUploadItemsFromDb();
|
|
swipeListRefreshLayout.setRefreshing(false);
|
|
}
|
|
|
|
@Override
|
|
protected void onStart() {
|
|
super.onStart();
|
|
}
|
|
|
|
@Override
|
|
protected void onResume() {
|
|
Log_OC.v(TAG, "onResume() start");
|
|
super.onResume();
|
|
|
|
setDrawerMenuItemChecked(R.id.nav_uploads);
|
|
|
|
// Listen for upload messages
|
|
uploadMessagesReceiver = new UploadMessagesReceiver();
|
|
IntentFilter uploadIntentFilter = new IntentFilter();
|
|
uploadIntentFilter.addAction(FileUploadWorker.Companion.getUploadsAddedMessage());
|
|
uploadIntentFilter.addAction(FileUploadWorker.Companion.getUploadStartMessage());
|
|
uploadIntentFilter.addAction(FileUploadWorker.Companion.getUploadFinishMessage());
|
|
localBroadcastManager.registerReceiver(uploadMessagesReceiver, uploadIntentFilter);
|
|
|
|
Log_OC.v(TAG, "onResume() end");
|
|
|
|
}
|
|
|
|
@Override
|
|
protected void onPause() {
|
|
Log_OC.v(TAG, "onPause() start");
|
|
if (uploadMessagesReceiver != null) {
|
|
localBroadcastManager.unregisterReceiver(uploadMessagesReceiver);
|
|
uploadMessagesReceiver = null;
|
|
}
|
|
super.onPause();
|
|
Log_OC.v(TAG, "onPause() end");
|
|
}
|
|
|
|
@Override
|
|
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) {
|
|
|
|
int itemId = item.getItemId();
|
|
|
|
if (itemId == android.R.id.home) {
|
|
if (isDrawerOpen()) {
|
|
closeDrawer();
|
|
} else {
|
|
openDrawer();
|
|
}
|
|
} else if (itemId == R.id.action_toggle_global_pause) {
|
|
toggleGlobalPause(item);
|
|
} else {
|
|
return super.onOptionsItemSelected(item);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
super.onActivityResult(requestCode, resultCode, data);
|
|
if (requestCode == FileActivity.REQUEST_CODE__UPDATE_CREDENTIALS && resultCode == RESULT_OK) {
|
|
FilesSyncHelper.restartJobsIfNeeded(uploadsStorageManager,
|
|
userAccountManager,
|
|
connectivityService,
|
|
powerManagementService);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param operation Operation performed.
|
|
* @param result Result of the removal.
|
|
*/
|
|
@Override
|
|
public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
|
|
if (operation instanceof CheckCurrentCredentialsOperation) {
|
|
// Do not call super in this case; more refactoring needed around onRemoteOperationFinish :'(
|
|
getFileOperationsHelper().setOpIdWaitingFor(Long.MAX_VALUE);
|
|
dismissLoadingDialog();
|
|
Account account = (Account) result.getData().get(0);
|
|
if (!result.isSuccess()) {
|
|
requestCredentialsUpdate(this, account);
|
|
|
|
} else {
|
|
// already updated -> just retry!
|
|
FilesSyncHelper.restartJobsIfNeeded(uploadsStorageManager,
|
|
userAccountManager,
|
|
connectivityService,
|
|
powerManagementService);
|
|
}
|
|
|
|
} else {
|
|
super.onRemoteOperationFinish(operation, result);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Once the file upload has changed its status -> update uploads list view
|
|
*/
|
|
private class UploadMessagesReceiver extends BroadcastReceiver {
|
|
/**
|
|
* {@link BroadcastReceiver} to enable syncing feedback in UI
|
|
*/
|
|
@Override
|
|
public void onReceive(Context context, Intent intent) {
|
|
|
|
throttler.run("update_upload_list", () -> {
|
|
uploadListAdapter.loadUploadItemsFromDb();
|
|
});
|
|
}
|
|
}
|
|
}
|