mirror of
https://github.com/nextcloud/android.git
synced 2024-12-20 16:02:01 +03:00
Merge remote-tracking branch 'origin/master' into dev
This commit is contained in:
commit
369c22266f
28 changed files with 877 additions and 937 deletions
|
@ -32,7 +32,7 @@ services:
|
|||
image: ghcr.io/nextcloud/continuous-integration-shallow-server:latest # also change in updateScreenshots.sh
|
||||
environment:
|
||||
EVAL: true
|
||||
SERVER_VERSION: 'stable25'
|
||||
SERVER_VERSION: 'stable27'
|
||||
commands:
|
||||
- BRANCH="$SERVER_VERSION" /usr/local/bin/initnc.sh
|
||||
- echo 127.0.0.1 server >> /etc/hosts
|
||||
|
@ -171,4 +171,6 @@ name: GIT_TOKEN
|
|||
data: XIoa9IYq+xQ+N5iln8dlpWv0jV6ROr7HuE24ioUr4uQ8m8SjyH0yognWYLYLqnbTKrFWlFZiEMQTH/sZiWjRFvV1iL0=
|
||||
---
|
||||
kind: signature
|
||||
hmac: aec1cabcb7b4f98f1be1d5b7a052a629ce3193e19a3692dd52ada48b6e72a1c9
|
||||
hmac: b78dcc477ff74ccbd7877df011090783847f8b5215a994be6597408bd735b524
|
||||
|
||||
...
|
||||
|
|
|
@ -25,6 +25,8 @@ import android.app.Activity
|
|||
import androidx.test.espresso.Espresso
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.action.ViewActions.click
|
||||
import androidx.test.espresso.action.ViewActions.closeSoftKeyboard
|
||||
import androidx.test.espresso.action.ViewActions.scrollTo
|
||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||
import androidx.test.espresso.contrib.DrawerActions
|
||||
import androidx.test.espresso.contrib.NavigationViewActions
|
||||
|
@ -238,7 +240,10 @@ class FileDisplayActivityIT : AbstractOnServerIT() {
|
|||
onView(withId(R.id.sort_button)).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)))
|
||||
|
||||
// browse into folder
|
||||
onView(withId(R.id.list_root)).perform(
|
||||
onView(withId(R.id.list_root))
|
||||
.perform(scrollTo())
|
||||
.perform(closeSoftKeyboard())
|
||||
.perform(
|
||||
RecyclerViewActions.actionOnItemAtPosition<OCFileListItemViewHolder>(
|
||||
0,
|
||||
click()
|
||||
|
|
|
@ -128,11 +128,15 @@ public abstract class AbstractOnServerIT extends AbstractIT {
|
|||
|
||||
if (!remoteFile.getRemotePath().equals("/")) {
|
||||
if (remoteFile.isEncrypted()) {
|
||||
assertTrue(new ToggleEncryptionRemoteOperation(remoteFile.getLocalId(),
|
||||
ToggleEncryptionRemoteOperation operation = new ToggleEncryptionRemoteOperation(remoteFile.getLocalId(),
|
||||
remoteFile.getRemotePath(),
|
||||
false)
|
||||
false);
|
||||
|
||||
boolean operationResult = operation
|
||||
.execute(client)
|
||||
.isSuccess());
|
||||
.isSuccess();
|
||||
|
||||
assertTrue(operationResult);
|
||||
}
|
||||
|
||||
boolean removeResult = false;
|
||||
|
|
|
@ -26,7 +26,7 @@ import com.owncloud.android.R
|
|||
import com.owncloud.android.lib.resources.trashbin.model.TrashbinFile
|
||||
import com.owncloud.android.ui.trashbin.TrashbinRepository.LoadFolderCallback
|
||||
|
||||
class TrashbinLocalRepository(val testCase: TrashbinActivityIT.TestCase) : TrashbinRepository {
|
||||
class TrashbinLocalRepository(private val testCase: TrashbinActivityIT.TestCase) : TrashbinRepository {
|
||||
override fun emptyTrashbin(callback: TrashbinRepository.OperationCallback?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
|
|
@ -105,12 +105,19 @@ class MediaFoldersDetectionWork constructor(
|
|||
)
|
||||
val imageMediaFolderPaths: MutableList<String> = ArrayList()
|
||||
val videoMediaFolderPaths: MutableList<String> = ArrayList()
|
||||
|
||||
for (imageMediaFolder in imageMediaFolders) {
|
||||
imageMediaFolderPaths.add(imageMediaFolder.absolutePath)
|
||||
imageMediaFolder.absolutePath?.let {
|
||||
imageMediaFolderPaths.add(it)
|
||||
}
|
||||
}
|
||||
|
||||
for (videoMediaFolder in videoMediaFolders) {
|
||||
imageMediaFolderPaths.add(videoMediaFolder.absolutePath)
|
||||
videoMediaFolder.absolutePath?.let {
|
||||
imageMediaFolderPaths.add(it)
|
||||
}
|
||||
}
|
||||
|
||||
val arbitraryDataString = arbitraryDataProvider.getValue(ACCOUNT_NAME_GLOBAL, KEY_MEDIA_FOLDERS)
|
||||
if (!TextUtils.isEmpty(arbitraryDataString)) {
|
||||
mediaFoldersModel = gson.fromJson(arbitraryDataString, MediaFoldersModel::class.java)
|
||||
|
|
|
@ -198,17 +198,21 @@ class FirstRunActivity : BaseActivity(), ViewPager.OnPageChangeListener, Injecta
|
|||
this,
|
||||
object : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() {
|
||||
onFinish()
|
||||
val isFromAddAccount = intent.getBooleanExtra(EXTRA_ALLOW_CLOSE, false)
|
||||
|
||||
if (intent.getBooleanExtra(EXTRA_ALLOW_CLOSE, false)) {
|
||||
onBackPressedDispatcher.onBackPressed()
|
||||
val destination: Intent = if (isFromAddAccount) {
|
||||
Intent(applicationContext, FileDisplayActivity::class.java)
|
||||
} else {
|
||||
val intent = Intent(applicationContext, AuthenticatorActivity::class.java)
|
||||
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||
intent.putExtra(EXTRA_EXIT, true)
|
||||
startActivity(intent)
|
||||
finish()
|
||||
Intent(applicationContext, AuthenticatorActivity::class.java)
|
||||
}
|
||||
|
||||
if (!isFromAddAccount) {
|
||||
destination.putExtra(EXTRA_EXIT, true)
|
||||
}
|
||||
|
||||
destination.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||
startActivity(destination)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
|
@ -254,11 +254,14 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector {
|
|||
|
||||
if (!isCrashReportingProcess && !appInfo.isDebugBuild()) {
|
||||
Thread.UncaughtExceptionHandler defaultPlatformHandler = Thread.getDefaultUncaughtExceptionHandler();
|
||||
|
||||
if (defaultPlatformHandler != null) {
|
||||
final ExceptionHandler crashReporter = new ExceptionHandler(this,
|
||||
defaultPlatformHandler);
|
||||
Thread.setDefaultUncaughtExceptionHandler(crashReporter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void initDagger() {
|
||||
appComponent = DaggerAppComponent.builder()
|
||||
|
@ -791,7 +794,10 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector {
|
|||
+ syncedFolder.getId() + " - " + syncedFolder.getLocalPath());
|
||||
|
||||
for (MediaFolder imageMediaFolder : imageMediaFolders) {
|
||||
if (imageMediaFolder.absolutePath.equals(syncedFolder.getLocalPath())) {
|
||||
String absolutePathOfImageFolder = imageMediaFolder.absolutePath;
|
||||
|
||||
if (absolutePathOfImageFolder != null) {
|
||||
if (absolutePathOfImageFolder.equals(syncedFolder.getLocalPath())) {
|
||||
newSyncedFolder = (SyncedFolder) syncedFolder.clone();
|
||||
newSyncedFolder.setType(MediaFolderType.IMAGE);
|
||||
primaryKey = syncedFolderProvider.storeSyncedFolder(newSyncedFolder);
|
||||
|
@ -800,9 +806,13 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector {
|
|||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (MediaFolder videoMediaFolder : videoMediaFolders) {
|
||||
if (videoMediaFolder.absolutePath.equals(syncedFolder.getLocalPath())) {
|
||||
String absolutePathOfVideoFolder = videoMediaFolder.absolutePath;
|
||||
|
||||
if (absolutePathOfVideoFolder != null) {
|
||||
if (absolutePathOfVideoFolder.equals(syncedFolder.getLocalPath())) {
|
||||
newSyncedFolder = (SyncedFolder) syncedFolder.clone();
|
||||
newSyncedFolder.setType(MediaFolderType.VIDEO);
|
||||
primaryKey = syncedFolderProvider.storeSyncedFolder(newSyncedFolder);
|
||||
|
@ -811,6 +821,8 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector {
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
for (long id : idsToDelete) {
|
||||
|
@ -835,19 +847,22 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector {
|
|||
|
||||
List<SyncedFolder> syncedFolderList = syncedFolderProvider.getSyncedFolders();
|
||||
Map<Pair<String, String>, Long> syncedFolders = new HashMap<>();
|
||||
ArrayList<Long> ids = new ArrayList<>();
|
||||
for (SyncedFolder syncedFolder : syncedFolderList) {
|
||||
Pair<String, String> checkPair = new Pair<>(syncedFolder.getAccount(), syncedFolder.getLocalPath());
|
||||
if (syncedFolders.containsKey(checkPair)) {
|
||||
if (syncedFolder.getId() > syncedFolders.get(checkPair)) {
|
||||
Long folderId = syncedFolders.get(checkPair);
|
||||
|
||||
if (folderId != null) {
|
||||
if (syncedFolder.getId() > folderId) {
|
||||
syncedFolders.put(checkPair, syncedFolder.getId());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
syncedFolders.put(checkPair, syncedFolder.getId());
|
||||
}
|
||||
}
|
||||
|
||||
ids.addAll(syncedFolders.values());
|
||||
ArrayList<Long> ids = new ArrayList<>(syncedFolders.values());
|
||||
|
||||
if (ids.size() > 0) {
|
||||
int deletedCount = syncedFolderProvider.deleteSyncedFoldersNotInList(ids);
|
||||
|
@ -865,18 +880,11 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector {
|
|||
return dispatchingAndroidInjector;
|
||||
}
|
||||
|
||||
|
||||
public static void setAppTheme(DarkMode mode) {
|
||||
switch (mode) {
|
||||
case LIGHT:
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
|
||||
break;
|
||||
case DARK:
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
|
||||
break;
|
||||
case SYSTEM:
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
|
||||
break;
|
||||
case LIGHT -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
|
||||
case DARK -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
|
||||
case SYSTEM -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
package com.owncloud.android.authentication;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.nextcloud.client.di.Injectable;
|
||||
import com.owncloud.android.R;
|
||||
|
||||
public class DeepLinkLoginActivity extends AuthenticatorActivity implements Injectable {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
if (!getResources().getBoolean(R.bool.multiaccount_support) &&
|
||||
accountManager.getAccounts().length == 1) {
|
||||
Toast.makeText(this, R.string.no_mutliple_accounts_allowed, Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
|
||||
setContentView(R.layout.deep_link_login);
|
||||
|
||||
Uri data = getIntent().getData();
|
||||
|
||||
if (data != null) {
|
||||
try {
|
||||
String prefix = getString(R.string.login_data_own_scheme) + PROTOCOL_SUFFIX + "login/";
|
||||
LoginUrlInfo loginUrlInfo = parseLoginDataUrl(prefix, data.toString());
|
||||
|
||||
TextView loginText = findViewById(R.id.loginInfo);
|
||||
loginText.setText(String.format(getString(R.string.direct_login_text), loginUrlInfo.username,
|
||||
loginUrlInfo.serverAddress));
|
||||
} catch (IllegalArgumentException e) {
|
||||
Toast.makeText(this, R.string.direct_login_failed, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package com.owncloud.android.authentication
|
||||
|
||||
import android.os.Bundle
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import com.nextcloud.client.di.Injectable
|
||||
import com.owncloud.android.R
|
||||
|
||||
class DeepLinkLoginActivity : AuthenticatorActivity(), Injectable {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
if (!resources.getBoolean(R.bool.multiaccount_support) &&
|
||||
accountManager.accounts.size == 1
|
||||
) {
|
||||
Toast.makeText(this, R.string.no_mutliple_accounts_allowed, Toast.LENGTH_LONG).show()
|
||||
return
|
||||
}
|
||||
|
||||
setContentView(R.layout.deep_link_login)
|
||||
|
||||
intent.data?.let {
|
||||
try {
|
||||
val prefix = getString(R.string.login_data_own_scheme) + PROTOCOL_SUFFIX + "login/"
|
||||
val loginUrlInfo = parseLoginDataUrl(prefix, it.toString())
|
||||
val loginText = findViewById<TextView>(R.id.loginInfo)
|
||||
loginText.text = String.format(
|
||||
getString(R.string.direct_login_text), loginUrlInfo.username,
|
||||
loginUrlInfo.serverAddress
|
||||
)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
Toast.makeText(this, R.string.direct_login_failed, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,29 +16,31 @@
|
|||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* License along with this program. If not, see <http:></http:>//www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.owncloud.android.datamodel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
package com.owncloud.android.datamodel
|
||||
|
||||
/**
|
||||
* Business object representing a media folder with all information that are gathered via media queries.
|
||||
*/
|
||||
public class MediaFolder {
|
||||
class MediaFolder {
|
||||
/** name of the folder. */
|
||||
public String folderName;
|
||||
@JvmField
|
||||
var folderName: String? = null
|
||||
|
||||
/** absolute path of the folder. */
|
||||
public String absolutePath;
|
||||
@JvmField
|
||||
var absolutePath: String? = null
|
||||
|
||||
/** list of file paths of the folder's content */
|
||||
public List<String> filePaths = new ArrayList<>();
|
||||
@JvmField
|
||||
var filePaths: List<String> = ArrayList()
|
||||
|
||||
/** total number of files in the media folder. */
|
||||
public long numberOfFiles;
|
||||
@JvmField
|
||||
var numberOfFiles: Long = 0
|
||||
|
||||
/** type of media folder. */
|
||||
public MediaFolderType type;
|
||||
@JvmField
|
||||
var type: MediaFolderType? = null
|
||||
}
|
|
@ -17,37 +17,28 @@
|
|||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.owncloud.android.datamodel;
|
||||
package com.owncloud.android.datamodel
|
||||
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseArray
|
||||
|
||||
/**
|
||||
* Types of media folder.
|
||||
*/
|
||||
public enum MediaFolderType {
|
||||
CUSTOM(0),
|
||||
IMAGE(1),
|
||||
VIDEO(2);
|
||||
enum class MediaFolderType(@JvmField val id: Int) {
|
||||
CUSTOM(0), IMAGE(1), VIDEO(2);
|
||||
|
||||
private Integer id;
|
||||
companion object {
|
||||
private val reverseMap = SparseArray<MediaFolderType>(3)
|
||||
|
||||
private static SparseArray<MediaFolderType> reverseMap = new SparseArray<>(3);
|
||||
|
||||
static {
|
||||
reverseMap.put(CUSTOM.getId(), CUSTOM);
|
||||
reverseMap.put(IMAGE.getId(), IMAGE);
|
||||
reverseMap.put(VIDEO.getId(), VIDEO);
|
||||
init {
|
||||
reverseMap.put(CUSTOM.id, CUSTOM)
|
||||
reverseMap.put(IMAGE.id, IMAGE)
|
||||
reverseMap.put(VIDEO.id, VIDEO)
|
||||
}
|
||||
|
||||
MediaFolderType(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public static MediaFolderType getById(Integer id) {
|
||||
return reverseMap.get(id);
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return this.id;
|
||||
@JvmStatic
|
||||
fun getById(id: Int?): MediaFolderType {
|
||||
return reverseMap[id!!]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Mario Danic
|
||||
* @author Andy Scherzinger
|
||||
* Copyright (C) 2018 Mario Danic
|
||||
* Copyright (C) 2018 Andy Scherzinger
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.owncloud.android.datamodel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class MediaFoldersModel {
|
||||
private List<String> imageMediaFolders;
|
||||
private List<String> videoMediaFolders;
|
||||
|
||||
public MediaFoldersModel(List<String> imageMediaFolders, List<String> videoMediaFolders) {
|
||||
this.imageMediaFolders = imageMediaFolders;
|
||||
this.videoMediaFolders = videoMediaFolders;
|
||||
}
|
||||
|
||||
public List<String> getImageMediaFolders() {
|
||||
return this.imageMediaFolders;
|
||||
}
|
||||
|
||||
public List<String> getVideoMediaFolders() {
|
||||
return this.videoMediaFolders;
|
||||
}
|
||||
|
||||
public void setImageMediaFolders(List<String> imageMediaFolders) {
|
||||
this.imageMediaFolders = imageMediaFolders;
|
||||
}
|
||||
|
||||
public void setVideoMediaFolders(List<String> videoMediaFolders) {
|
||||
this.videoMediaFolders = videoMediaFolders;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Mario Danic
|
||||
* @author Andy Scherzinger
|
||||
* Copyright (C) 2018 Mario Danic
|
||||
* Copyright (C) 2018 Andy Scherzinger
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.owncloud.android.datamodel
|
||||
|
||||
class MediaFoldersModel(var imageMediaFolders: List<String>, var videoMediaFolders: List<String>)
|
|
@ -415,7 +415,7 @@ public class SyncedFolderProvider extends Observable {
|
|||
cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_UPLOAD_ACTION, syncedFolder.getUploadAction());
|
||||
cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_NAME_COLLISION_POLICY,
|
||||
syncedFolder.getNameCollisionPolicyInt());
|
||||
cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_TYPE, syncedFolder.getType().getId());
|
||||
cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_TYPE, syncedFolder.getType().id);
|
||||
cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_HIDDEN, syncedFolder.isHidden());
|
||||
cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_SUBFOLDER_RULE, syncedFolder.getSubfolderRule().ordinal());
|
||||
|
||||
|
|
|
@ -779,6 +779,13 @@ public abstract class FileActivity extends DrawerActivity
|
|||
}
|
||||
}
|
||||
|
||||
public void refreshList() {
|
||||
final Fragment fileListFragment = getSupportFragmentManager().findFragmentByTag(FileDisplayActivity.TAG_LIST_OF_FILES);
|
||||
if (fileListFragment != null) {
|
||||
((OCFileListFragment) fileListFragment).onRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
private void onCreateShareViaLinkOperationFinish(CreateShareViaLinkOperation operation,
|
||||
RemoteOperationResult result) {
|
||||
FileDetailSharingFragment sharingFragment = getShareFileFragment();
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
package com.owncloud.android.ui.adapter;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
|
@ -94,15 +95,15 @@ public class ShareeListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
|
|||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
switch (ShareType.fromValue(viewType)) {
|
||||
case PUBLIC_LINK:
|
||||
case EMAIL:
|
||||
case PUBLIC_LINK, EMAIL -> {
|
||||
return new LinkShareViewHolder(
|
||||
FileDetailsShareLinkShareItemBinding.inflate(LayoutInflater.from(fileActivity),
|
||||
parent,
|
||||
false),
|
||||
fileActivity,
|
||||
viewThemeUtils);
|
||||
case NEW_PUBLIC_LINK:
|
||||
}
|
||||
case NEW_PUBLIC_LINK -> {
|
||||
if (encrypted) {
|
||||
return new NewSecureFileDropViewHolder(
|
||||
FileDetailsShareSecureFileDropAddNewItemBinding.inflate(LayoutInflater.from(fileActivity),
|
||||
|
@ -116,11 +117,13 @@ public class ShareeListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
|
|||
false)
|
||||
);
|
||||
}
|
||||
case INTERNAL:
|
||||
}
|
||||
case INTERNAL -> {
|
||||
return new InternalShareViewHolder(
|
||||
FileDetailsShareInternalShareLinkBinding.inflate(LayoutInflater.from(fileActivity), parent, false),
|
||||
fileActivity);
|
||||
default:
|
||||
}
|
||||
default -> {
|
||||
return new ShareViewHolder(FileDetailsShareShareItemBinding.inflate(LayoutInflater.from(fileActivity),
|
||||
parent,
|
||||
false),
|
||||
|
@ -129,6 +132,7 @@ public class ShareeListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
|
|||
viewThemeUtils);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
|
||||
|
@ -138,17 +142,13 @@ public class ShareeListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
|
|||
|
||||
final OCShare share = shares.get(position);
|
||||
|
||||
if (holder instanceof LinkShareViewHolder) {
|
||||
LinkShareViewHolder publicShareViewHolder = (LinkShareViewHolder) holder;
|
||||
if (holder instanceof LinkShareViewHolder publicShareViewHolder) {
|
||||
publicShareViewHolder.bind(share, listener);
|
||||
} else if (holder instanceof InternalShareViewHolder) {
|
||||
InternalShareViewHolder internalShareViewHolder = (InternalShareViewHolder) holder;
|
||||
} else if (holder instanceof InternalShareViewHolder internalShareViewHolder) {
|
||||
internalShareViewHolder.bind(share, listener);
|
||||
} else if (holder instanceof NewLinkShareViewHolder) {
|
||||
NewLinkShareViewHolder newLinkShareViewHolder = (NewLinkShareViewHolder) holder;
|
||||
} else if (holder instanceof NewLinkShareViewHolder newLinkShareViewHolder) {
|
||||
newLinkShareViewHolder.bind(listener);
|
||||
} else if (holder instanceof NewSecureFileDropViewHolder) {
|
||||
NewSecureFileDropViewHolder newSecureFileDropViewHolder = (NewSecureFileDropViewHolder) holder;
|
||||
} else if (holder instanceof NewSecureFileDropViewHolder newSecureFileDropViewHolder) {
|
||||
newSecureFileDropViewHolder.bind(listener);
|
||||
} else {
|
||||
ShareViewHolder userViewHolder = (ShareViewHolder) holder;
|
||||
|
@ -166,6 +166,7 @@ public class ShareeListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
|
|||
return shares.size();
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
public void addShares(List<OCShare> sharesToAdd) {
|
||||
shares.addAll(sharesToAdd);
|
||||
sortShares();
|
||||
|
@ -174,22 +175,21 @@ public class ShareeListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
|
|||
|
||||
@Override
|
||||
public void avatarGenerated(Drawable avatarDrawable, Object callContext) {
|
||||
if (callContext instanceof ImageView) {
|
||||
ImageView iv = (ImageView) callContext;
|
||||
if (callContext instanceof ImageView iv) {
|
||||
iv.setImageDrawable(avatarDrawable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldCallGeneratedCallback(String tag, Object callContext) {
|
||||
if (callContext instanceof ImageView) {
|
||||
ImageView iv = (ImageView) callContext;
|
||||
if (callContext instanceof ImageView iv) {
|
||||
// needs to be changed once federated users have avatars
|
||||
return String.valueOf(iv.getTag()).equals(tag.split("@")[0]);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
public void remove(OCShare share) {
|
||||
shares.remove(share);
|
||||
notifyDataSetChanged();
|
||||
|
@ -210,8 +210,8 @@ public class ShareeListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
|
|||
}
|
||||
}
|
||||
|
||||
Collections.sort(links, (o1, o2) -> Long.compare(o2.getSharedDate(), o1.getSharedDate()));
|
||||
Collections.sort(users, (o1, o2) -> Long.compare(o2.getSharedDate(), o1.getSharedDate()));
|
||||
links.sort((o1, o2) -> Long.compare(o2.getSharedDate(), o1.getSharedDate()));
|
||||
users.sort((o1, o2) -> Long.compare(o2.getSharedDate(), o1.getSharedDate()));
|
||||
|
||||
shares = links;
|
||||
shares.addAll(users);
|
||||
|
|
|
@ -248,7 +248,7 @@ public class SyncedFolderAdapter extends SectionedRecyclerViewAdapter<SectionedV
|
|||
public int getSectionByLocalPathAndType(String localPath, int type) {
|
||||
for (int i = 0; i < filteredSyncFolderItems.size(); i++) {
|
||||
if (filteredSyncFolderItems.get(i).getLocalPath().equalsIgnoreCase(localPath) &&
|
||||
filteredSyncFolderItems.get(i).getType().getId().equals(type)) {
|
||||
filteredSyncFolderItems.get(i).getType().id == type) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,7 +105,7 @@ public class SyncedFolderParcelable implements Parcelable {
|
|||
dest.writeInt(existing ? 1 : 0);
|
||||
dest.writeInt(enabled ? 1 : 0);
|
||||
dest.writeInt(subfolderByDate ? 1 : 0);
|
||||
dest.writeInt(type.getId());
|
||||
dest.writeInt(type.id);
|
||||
dest.writeString(account);
|
||||
dest.writeInt(uploadAction);
|
||||
dest.writeInt(nameCollisionPolicy.serialize());
|
||||
|
|
|
@ -932,15 +932,15 @@ public class FileOperationsHelper {
|
|||
}
|
||||
|
||||
public void renameFile(OCFile file, String newFilename) {
|
||||
// RenameFile
|
||||
Intent service = new Intent(fileActivity, OperationsService.class);
|
||||
|
||||
service.setAction(OperationsService.ACTION_RENAME);
|
||||
service.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount());
|
||||
service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
|
||||
service.putExtra(OperationsService.EXTRA_NEWNAME, newFilename);
|
||||
mWaitingForOpId = fileActivity.getOperationsServiceBinder().queueNewOperation(service);
|
||||
|
||||
fileActivity.showLoadingDialog(fileActivity.getString(R.string.wait_a_moment));
|
||||
fileActivity.refreshList();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,227 +0,0 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* @author TSI-mc
|
||||
* @author Chris Narkiewicz
|
||||
*
|
||||
* Copyright (C) 2018 Tobias Kaminsky
|
||||
* Copyright (C) 2018 Nextcloud GmbH.
|
||||
* Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
|
||||
* Copyright (C) 2023 TSI-mc
|
||||
*
|
||||
* 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.trashbin;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import com.nextcloud.client.account.User;
|
||||
import com.nextcloud.client.network.ClientFactory;
|
||||
import com.nextcloud.common.NextcloudClient;
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.lib.common.OwnCloudClient;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.lib.resources.trashbin.EmptyTrashbinRemoteOperation;
|
||||
import com.owncloud.android.lib.resources.trashbin.ReadTrashbinFolderRemoteOperation;
|
||||
import com.owncloud.android.lib.resources.trashbin.RemoveTrashbinFileRemoteOperation;
|
||||
import com.owncloud.android.lib.resources.trashbin.RestoreTrashbinFileRemoteOperation;
|
||||
import com.owncloud.android.lib.resources.trashbin.model.TrashbinFile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public class RemoteTrashbinRepository implements TrashbinRepository {
|
||||
|
||||
private final User user;
|
||||
private final ClientFactory clientFactory;
|
||||
|
||||
RemoteTrashbinRepository(User user, ClientFactory clientFactory) {
|
||||
this.user = user;
|
||||
this.clientFactory = clientFactory;
|
||||
}
|
||||
|
||||
public void removeTrashbinFile(TrashbinFile file, OperationCallback callback) {
|
||||
new RemoveTrashbinFileTask(user, clientFactory, file, callback).execute();
|
||||
}
|
||||
|
||||
private static class RemoveTrashbinFileTask extends AsyncTask<Void, Void, Boolean> {
|
||||
|
||||
private User user;
|
||||
private ClientFactory clientFactory;
|
||||
private TrashbinFile file;
|
||||
private OperationCallback callback;
|
||||
|
||||
private RemoveTrashbinFileTask(User user,
|
||||
ClientFactory clientFactory,
|
||||
TrashbinFile file,
|
||||
OperationCallback callback) {
|
||||
this.user = user;
|
||||
this.clientFactory = clientFactory;
|
||||
this.file = file;
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... voids) {
|
||||
try {
|
||||
OwnCloudClient client = clientFactory.create(user);
|
||||
RemoteOperationResult result = new RemoveTrashbinFileRemoteOperation(file.getFullRemotePath())
|
||||
.execute(client);
|
||||
return result.isSuccess();
|
||||
} catch (ClientFactory.CreationException e) {
|
||||
Log_OC.e(this, "Cannot create client", e);
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean success) {
|
||||
super.onPostExecute(success);
|
||||
|
||||
callback.onResult(success);
|
||||
}
|
||||
}
|
||||
|
||||
public void emptyTrashbin(OperationCallback callback) {
|
||||
new EmptyTrashbinTask(user, clientFactory, callback).execute();
|
||||
}
|
||||
|
||||
private static class EmptyTrashbinTask extends AsyncTask<Void, Void, Boolean> {
|
||||
|
||||
private User user;
|
||||
private ClientFactory clientFactory;
|
||||
private OperationCallback callback;
|
||||
|
||||
private EmptyTrashbinTask(User user, ClientFactory clientFactory, OperationCallback callback) {
|
||||
this.user = user;
|
||||
this.clientFactory = clientFactory;
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... voids) {
|
||||
try {
|
||||
NextcloudClient client = clientFactory.createNextcloudClient(user);
|
||||
EmptyTrashbinRemoteOperation emptyTrashbinFileOperation = new EmptyTrashbinRemoteOperation();
|
||||
RemoteOperationResult<Boolean> result = emptyTrashbinFileOperation.execute(client);
|
||||
return result.isSuccess();
|
||||
} catch (ClientFactory.CreationException e) {
|
||||
Log_OC.e(this, "Cannot create client", e);
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean success) {
|
||||
super.onPostExecute(success);
|
||||
|
||||
callback.onResult(success);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreFile(TrashbinFile file, OperationCallback callback) {
|
||||
new RestoreTrashbinFileTask(file, user, clientFactory, callback).execute();
|
||||
}
|
||||
|
||||
private static class RestoreTrashbinFileTask extends AsyncTask<Void, Void, Boolean> {
|
||||
|
||||
private TrashbinFile file;
|
||||
private User user;
|
||||
private ClientFactory clientFactory;
|
||||
private TrashbinRepository.OperationCallback callback;
|
||||
|
||||
private RestoreTrashbinFileTask(TrashbinFile file, User user, ClientFactory clientFactory,
|
||||
TrashbinRepository.OperationCallback callback) {
|
||||
this.file = file;
|
||||
this.user = user;
|
||||
this.clientFactory = clientFactory;
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... voids) {
|
||||
try {
|
||||
OwnCloudClient client = clientFactory.create(user);
|
||||
RemoteOperationResult result = new RestoreTrashbinFileRemoteOperation(file.getFullRemotePath(),
|
||||
file.getFileName()).execute(client);
|
||||
|
||||
return result.isSuccess();
|
||||
} catch (ClientFactory.CreationException e) {
|
||||
Log_OC.e(this, "Cannot create client", e);
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean success) {
|
||||
super.onPostExecute(success);
|
||||
|
||||
callback.onResult(success);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getFolder(String remotePath, @NonNull LoadFolderCallback callback) {
|
||||
new ReadRemoteTrashbinFolderTask(remotePath, user, clientFactory, callback).execute();
|
||||
}
|
||||
|
||||
private static class ReadRemoteTrashbinFolderTask extends AsyncTask<Void, Void, Boolean> {
|
||||
|
||||
private String remotePath;
|
||||
private User user;
|
||||
private ClientFactory clientFactory;
|
||||
private List<TrashbinFile> trashbinFiles;
|
||||
private LoadFolderCallback callback;
|
||||
|
||||
private ReadRemoteTrashbinFolderTask(String remotePath, User user, ClientFactory clientFactory,
|
||||
LoadFolderCallback callback) {
|
||||
this.remotePath = remotePath;
|
||||
this.user = user;
|
||||
this.clientFactory = clientFactory;
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... voids) {
|
||||
try {
|
||||
OwnCloudClient client = clientFactory.create(user);
|
||||
RemoteOperationResult<List<TrashbinFile>> result =
|
||||
new ReadTrashbinFolderRemoteOperation(remotePath).execute(client);
|
||||
if (result.isSuccess()) {
|
||||
trashbinFiles = result.getResultData();
|
||||
return Boolean.TRUE;
|
||||
} else {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
} catch (ClientFactory.CreationException e) {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean success) {
|
||||
super.onPostExecute(success);
|
||||
|
||||
if (success) {
|
||||
callback.onSuccess(trashbinFiles);
|
||||
} else {
|
||||
callback.onError(R.string.trashbin_loading_failed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* @author TSI-mc
|
||||
* @author Chris Narkiewicz
|
||||
*
|
||||
* Copyright (C) 2018 Tobias Kaminsky
|
||||
* Copyright (C) 2018 Nextcloud GmbH.
|
||||
* Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
|
||||
* Copyright (C) 2023 TSI-mc
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package com.owncloud.android.ui.trashbin
|
||||
|
||||
import android.os.AsyncTask
|
||||
import com.nextcloud.client.account.User
|
||||
import com.nextcloud.client.network.ClientFactory
|
||||
import com.nextcloud.client.network.ClientFactory.CreationException
|
||||
import com.owncloud.android.R
|
||||
import com.owncloud.android.lib.common.utils.Log_OC
|
||||
import com.owncloud.android.lib.resources.trashbin.EmptyTrashbinRemoteOperation
|
||||
import com.owncloud.android.lib.resources.trashbin.ReadTrashbinFolderRemoteOperation
|
||||
import com.owncloud.android.lib.resources.trashbin.RemoveTrashbinFileRemoteOperation
|
||||
import com.owncloud.android.lib.resources.trashbin.RestoreTrashbinFileRemoteOperation
|
||||
import com.owncloud.android.lib.resources.trashbin.model.TrashbinFile
|
||||
import com.owncloud.android.ui.trashbin.TrashbinRepository.LoadFolderCallback
|
||||
import com.owncloud.android.ui.trashbin.TrashbinRepository.OperationCallback
|
||||
|
||||
class RemoteTrashbinRepository internal constructor(private val user: User, private val clientFactory: ClientFactory) :
|
||||
TrashbinRepository {
|
||||
|
||||
override fun removeTrashbinFile(file: TrashbinFile?, callback: OperationCallback?) {
|
||||
RemoveTrashbinFileTask(user, clientFactory, file, callback).execute()
|
||||
}
|
||||
|
||||
private class RemoveTrashbinFileTask(
|
||||
private val user: User,
|
||||
private val clientFactory: ClientFactory,
|
||||
private val file: TrashbinFile?,
|
||||
private val callback: OperationCallback?
|
||||
) : AsyncTask<Void?, Void?, Boolean>() {
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun doInBackground(vararg voids: Void?): Boolean {
|
||||
return try {
|
||||
val client = clientFactory.create(user)
|
||||
val result = RemoveTrashbinFileRemoteOperation(file!!.fullRemotePath)
|
||||
.execute(client)
|
||||
result.isSuccess
|
||||
} catch (e: CreationException) {
|
||||
Log_OC.e(this, "Cannot create client", e)
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun onPostExecute(success: Boolean) {
|
||||
super.onPostExecute(success)
|
||||
callback?.onResult(success)
|
||||
}
|
||||
}
|
||||
|
||||
override fun emptyTrashbin(callback: OperationCallback?) {
|
||||
EmptyTrashbinTask(user, clientFactory, callback).execute()
|
||||
}
|
||||
|
||||
private class EmptyTrashbinTask(
|
||||
private val user: User,
|
||||
private val clientFactory: ClientFactory,
|
||||
private val callback: OperationCallback?
|
||||
) : AsyncTask<Void?, Void?, Boolean>() {
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun doInBackground(vararg voids: Void?): Boolean {
|
||||
return try {
|
||||
val client = clientFactory.createNextcloudClient(user)
|
||||
val emptyTrashbinFileOperation = EmptyTrashbinRemoteOperation()
|
||||
val result = emptyTrashbinFileOperation.execute(client)
|
||||
result.isSuccess
|
||||
} catch (e: CreationException) {
|
||||
Log_OC.e(this, "Cannot create client", e)
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun onPostExecute(success: Boolean) {
|
||||
super.onPostExecute(success)
|
||||
callback?.onResult(success)
|
||||
}
|
||||
}
|
||||
|
||||
override fun restoreFile(file: TrashbinFile?, callback: OperationCallback?) {
|
||||
RestoreTrashbinFileTask(file, user, clientFactory, callback).execute()
|
||||
}
|
||||
|
||||
private class RestoreTrashbinFileTask(
|
||||
private val file: TrashbinFile?,
|
||||
private val user: User,
|
||||
private val clientFactory: ClientFactory,
|
||||
private val callback: OperationCallback?
|
||||
) : AsyncTask<Void?, Void?, Boolean>() {
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun doInBackground(vararg voids: Void?): Boolean {
|
||||
return try {
|
||||
val client = clientFactory.create(user)
|
||||
val result = RestoreTrashbinFileRemoteOperation(
|
||||
file!!.fullRemotePath,
|
||||
file.fileName
|
||||
).execute(client)
|
||||
result.isSuccess
|
||||
} catch (e: CreationException) {
|
||||
Log_OC.e(this, "Cannot create client", e)
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun onPostExecute(success: Boolean) {
|
||||
super.onPostExecute(success)
|
||||
callback?.onResult(success)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getFolder(remotePath: String?, callback: LoadFolderCallback?) {
|
||||
callback?.let {
|
||||
ReadRemoteTrashbinFolderTask(remotePath, user, clientFactory, it).execute()
|
||||
}
|
||||
}
|
||||
|
||||
private class ReadRemoteTrashbinFolderTask(
|
||||
private val remotePath: String?,
|
||||
private val user: User,
|
||||
private val clientFactory: ClientFactory,
|
||||
private val callback: LoadFolderCallback
|
||||
) : AsyncTask<Void?, Void?, Boolean>() {
|
||||
private var trashbinFiles: List<TrashbinFile?>? = null
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun doInBackground(vararg voids: Void?): Boolean {
|
||||
return try {
|
||||
val client = clientFactory.create(user)
|
||||
val result = ReadTrashbinFolderRemoteOperation(remotePath).execute(client)
|
||||
if (result.isSuccess) {
|
||||
trashbinFiles = result.resultData
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} catch (e: CreationException) {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun onPostExecute(success: Boolean) {
|
||||
super.onPostExecute(success)
|
||||
|
||||
if (success) {
|
||||
callback.onSuccess(trashbinFiles)
|
||||
} else {
|
||||
callback.onError(R.string.trashbin_loading_failed)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,334 +0,0 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* @author Chris Narkiewicz
|
||||
*
|
||||
* Copyright (C) 2018 Tobias Kaminsky
|
||||
* Copyright (C) 2018 Nextcloud GmbH.
|
||||
* Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
|
||||
*
|
||||
* 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.trashbin;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.PopupMenu;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import com.nextcloud.client.account.CurrentAccountProvider;
|
||||
import com.nextcloud.client.account.User;
|
||||
import com.nextcloud.client.di.Injectable;
|
||||
import com.nextcloud.client.network.ClientFactory;
|
||||
import com.nextcloud.client.preferences.AppPreferences;
|
||||
import com.nextcloud.java.util.Optional;
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.databinding.TrashbinActivityBinding;
|
||||
import com.owncloud.android.lib.resources.trashbin.model.TrashbinFile;
|
||||
import com.owncloud.android.ui.EmptyRecyclerView;
|
||||
import com.owncloud.android.ui.activity.DrawerActivity;
|
||||
import com.owncloud.android.ui.adapter.TrashbinListAdapter;
|
||||
import com.owncloud.android.ui.dialog.SortingOrderDialogFragment;
|
||||
import com.owncloud.android.ui.interfaces.TrashbinActivityInterface;
|
||||
import com.owncloud.android.utils.DisplayUtils;
|
||||
import com.owncloud.android.utils.FileSortOrder;
|
||||
import com.owncloud.android.utils.theme.ViewThemeUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.core.content.res.ResourcesCompat;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
|
||||
import static com.owncloud.android.utils.DisplayUtils.openSortingOrderDialogFragment;
|
||||
|
||||
/**
|
||||
* Presenting trashbin data, received from presenter
|
||||
*/
|
||||
public class TrashbinActivity extends DrawerActivity implements
|
||||
TrashbinActivityInterface,
|
||||
SortingOrderDialogFragment.OnSortingOrderListener,
|
||||
TrashbinContract.View,
|
||||
Injectable {
|
||||
|
||||
public static final int EMPTY_LIST_COUNT = 1;
|
||||
@Inject AppPreferences preferences;
|
||||
@Inject CurrentAccountProvider accountProvider;
|
||||
@Inject ClientFactory clientFactory;
|
||||
@Inject ViewThemeUtils viewThemeUtils;
|
||||
|
||||
private TrashbinListAdapter trashbinListAdapter;
|
||||
|
||||
@VisibleForTesting
|
||||
TrashbinPresenter trashbinPresenter;
|
||||
|
||||
private boolean active;
|
||||
private TrashbinActivityBinding binding;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
final User currentUser = getUser().orElse(accountProvider.getUser());
|
||||
final String targetAccount = getIntent().getStringExtra(Intent.EXTRA_USER);
|
||||
if (targetAccount != null && !currentUser.nameEquals(targetAccount)) {
|
||||
final Optional<User> targetUser = getUserAccountManager().getUser(targetAccount);
|
||||
if (targetUser.isPresent()) {
|
||||
setUser(targetUser.get());
|
||||
} else {
|
||||
Toast.makeText(this, R.string.associated_account_not_found, Toast.LENGTH_LONG).show();
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
final RemoteTrashbinRepository trashRepository =
|
||||
new RemoteTrashbinRepository(getUser().orElse(accountProvider.getUser()), clientFactory);
|
||||
trashbinPresenter = new TrashbinPresenter(trashRepository, this);
|
||||
|
||||
binding = TrashbinActivityBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
setupToolbar();
|
||||
findViewById(R.id.sort_list_button_group).setVisibility(View.VISIBLE);
|
||||
findViewById(R.id.switch_grid_view_button).setVisibility(View.GONE);
|
||||
updateActionBarTitleAndHomeButtonByString(getString(R.string.trashbin_activity_title));
|
||||
setupDrawer(R.id.nav_trashbin);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
active = true;
|
||||
setupContent();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
setDrawerMenuItemChecked(R.id.nav_trashbin);
|
||||
}
|
||||
|
||||
private void setupContent() {
|
||||
EmptyRecyclerView recyclerView = binding.list;
|
||||
recyclerView.setEmptyView(binding.emptyList.emptyListView);
|
||||
binding.emptyList.emptyListView.setVisibility(View.GONE);
|
||||
binding.emptyList.emptyListIcon.setImageResource(R.drawable.ic_delete);
|
||||
binding.emptyList.emptyListIcon.setVisibility(View.VISIBLE);
|
||||
binding.emptyList.emptyListViewHeadline.setText(getString(R.string.trashbin_empty_headline));
|
||||
binding.emptyList.emptyListViewText.setText(getString(R.string.trashbin_empty_message));
|
||||
binding.emptyList.emptyListViewText.setVisibility(View.VISIBLE);
|
||||
|
||||
trashbinListAdapter = new TrashbinListAdapter(
|
||||
this,
|
||||
getStorageManager(),
|
||||
preferences,
|
||||
this,
|
||||
getUser().orElse(accountProvider.getUser()),
|
||||
viewThemeUtils
|
||||
);
|
||||
recyclerView.setAdapter(trashbinListAdapter);
|
||||
recyclerView.setHasFixedSize(true);
|
||||
recyclerView.setHasFooter(true);
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(this));
|
||||
|
||||
viewThemeUtils.androidx.themeSwipeRefreshLayout(binding.swipeContainingList);
|
||||
binding.swipeContainingList.setOnRefreshListener(this::loadFolder);
|
||||
|
||||
viewThemeUtils.material.colorMaterialTextButton(findViewById(R.id.sort_button));
|
||||
|
||||
findViewById(R.id.sort_button).setOnClickListener(l ->
|
||||
openSortingOrderDialogFragment(getSupportFragmentManager(),
|
||||
preferences.getSortOrderByType(
|
||||
FileSortOrder.Type.trashBinView,
|
||||
FileSortOrder.sort_new_to_old))
|
||||
);
|
||||
|
||||
loadFolder();
|
||||
}
|
||||
|
||||
protected void loadFolder() {
|
||||
if (trashbinListAdapter.getItemCount() > EMPTY_LIST_COUNT) {
|
||||
binding.swipeContainingList.setRefreshing(true);
|
||||
} else {
|
||||
showInitialLoading();
|
||||
}
|
||||
trashbinPresenter.loadFolder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
boolean retval = true;
|
||||
int itemId = item.getItemId();
|
||||
if (itemId == android.R.id.home) {
|
||||
if (isDrawerOpen()) {
|
||||
closeDrawer();
|
||||
} else if (trashbinPresenter.isRoot()) {
|
||||
onBackPressed();
|
||||
} else {
|
||||
openDrawer();
|
||||
}
|
||||
} else if (itemId == R.id.action_empty_trashbin) {
|
||||
trashbinPresenter.emptyTrashbin();
|
||||
} else {
|
||||
retval = super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOverflowIconClicked(TrashbinFile file, View view) {
|
||||
PopupMenu popup = new PopupMenu(this, view);
|
||||
popup.inflate(R.menu.item_trashbin);
|
||||
|
||||
popup.setOnMenuItemClickListener(item -> {
|
||||
trashbinPresenter.removeTrashbinFile(file);
|
||||
|
||||
return true;
|
||||
});
|
||||
popup.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClicked(TrashbinFile file) {
|
||||
if (file.isFolder()) {
|
||||
trashbinPresenter.enterFolder(file.getRemotePath());
|
||||
|
||||
mDrawerToggle.setDrawerIndicatorEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestoreIconClicked(TrashbinFile file, View view) {
|
||||
trashbinPresenter.restoreTrashbinFile(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.activity_trashbin, menu);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
active = false;
|
||||
|
||||
trashbinListAdapter.cancelAllPendingTasks();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
trashbinPresenter.navigateUp();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
super.onBackPressed();
|
||||
}
|
||||
|
||||
public void setDrawerIndicatorEnabled(boolean bool) {
|
||||
mDrawerToggle.setDrawerIndicatorEnabled(bool);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onSortingOrderChosen(FileSortOrder sortOrder) {
|
||||
TextView sortButton = findViewById(R.id.sort_button);
|
||||
sortButton.setText(DisplayUtils.getSortOrderStringId(sortOrder));
|
||||
trashbinListAdapter.setSortOrder(sortOrder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showTrashbinFolder(List<TrashbinFile> trashbinFiles) {
|
||||
if (active) {
|
||||
trashbinListAdapter.setTrashbinFiles(trashbinFiles, true);
|
||||
binding.swipeContainingList.setRefreshing(false);
|
||||
binding.loadingContent.setVisibility(View.GONE);
|
||||
binding.emptyList.emptyListIcon.setImageResource(R.drawable.ic_delete);
|
||||
binding.emptyList.emptyListViewHeadline.setText(getString(R.string.trashbin_empty_headline));
|
||||
binding.emptyList.emptyListViewText.setText(getString(R.string.trashbin_empty_message));
|
||||
binding.list.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFile(TrashbinFile file) {
|
||||
if (active) {
|
||||
trashbinListAdapter.removeFile(file);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllFiles() {
|
||||
trashbinListAdapter.removeAllFiles();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showSnackbarError(int message, TrashbinFile file) {
|
||||
if (active) {
|
||||
binding.swipeContainingList.setRefreshing(false);
|
||||
Snackbar.make(binding.list,
|
||||
String.format(getString(message), file.getFileName()), Snackbar.LENGTH_LONG)
|
||||
.show();
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void showInitialLoading() {
|
||||
binding.emptyList.emptyListView.setVisibility(View.GONE);
|
||||
binding.list.setVisibility(View.GONE);
|
||||
binding.loadingContent.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void showUser() {
|
||||
binding.loadingContent.setVisibility(View.GONE);
|
||||
binding.list.setVisibility(View.VISIBLE);
|
||||
binding.swipeContainingList.setRefreshing(false);
|
||||
|
||||
binding.emptyList.emptyListViewText.setText(getUser().get().getAccountName());
|
||||
binding.emptyList.emptyListViewText.setVisibility(View.VISIBLE);
|
||||
binding.emptyList.emptyListView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showError(int message) {
|
||||
if (active) {
|
||||
trashbinListAdapter.removeAllFiles();
|
||||
|
||||
binding.loadingContent.setVisibility(View.GONE);
|
||||
binding.list.setVisibility(View.VISIBLE);
|
||||
binding.swipeContainingList.setRefreshing(false);
|
||||
|
||||
binding.emptyList.emptyListViewHeadline.setText(R.string.common_error);
|
||||
binding.emptyList.emptyListIcon.setImageDrawable(ResourcesCompat.getDrawable(getResources(),
|
||||
R.drawable.ic_list_empty_error,
|
||||
null));
|
||||
binding.emptyList.emptyListViewText.setText(message);
|
||||
binding.emptyList.emptyListViewText.setVisibility(View.VISIBLE);
|
||||
binding.emptyList.emptyListIcon.setVisibility(View.VISIBLE);
|
||||
binding.emptyList.emptyListView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,340 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* @author Chris Narkiewicz
|
||||
*
|
||||
* Copyright (C) 2018 Tobias Kaminsky
|
||||
* Copyright (C) 2018 Nextcloud GmbH.
|
||||
* Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
|
||||
*
|
||||
* 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.trashbin
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.PopupMenu
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.nextcloud.client.account.CurrentAccountProvider
|
||||
import com.nextcloud.client.di.Injectable
|
||||
import com.nextcloud.client.network.ClientFactory
|
||||
import com.nextcloud.client.preferences.AppPreferences
|
||||
import com.owncloud.android.R
|
||||
import com.owncloud.android.databinding.TrashbinActivityBinding
|
||||
import com.owncloud.android.lib.resources.trashbin.model.TrashbinFile
|
||||
import com.owncloud.android.ui.activity.DrawerActivity
|
||||
import com.owncloud.android.ui.adapter.TrashbinListAdapter
|
||||
import com.owncloud.android.ui.dialog.SortingOrderDialogFragment.OnSortingOrderListener
|
||||
import com.owncloud.android.ui.interfaces.TrashbinActivityInterface
|
||||
import com.owncloud.android.utils.DisplayUtils
|
||||
import com.owncloud.android.utils.FileSortOrder
|
||||
import com.owncloud.android.utils.theme.ViewThemeUtils
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Presenting trashbin data, received from presenter
|
||||
*/
|
||||
class TrashbinActivity :
|
||||
DrawerActivity(),
|
||||
TrashbinActivityInterface,
|
||||
OnSortingOrderListener,
|
||||
TrashbinContract.View,
|
||||
Injectable {
|
||||
|
||||
@JvmField
|
||||
@Inject
|
||||
var preferences: AppPreferences? = null
|
||||
|
||||
@JvmField
|
||||
@Inject
|
||||
var accountProvider: CurrentAccountProvider? = null
|
||||
|
||||
@JvmField
|
||||
@Inject
|
||||
var clientFactory: ClientFactory? = null
|
||||
|
||||
@JvmField
|
||||
@Inject
|
||||
var viewThemeUtils: ViewThemeUtils? = null
|
||||
|
||||
private var trashbinListAdapter: TrashbinListAdapter? = null
|
||||
|
||||
@VisibleForTesting
|
||||
var trashbinPresenter: TrashbinPresenter? = null
|
||||
|
||||
private var active = false
|
||||
private lateinit var binding: TrashbinActivityBinding
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
val currentUser = user.orElse(accountProvider!!.user)
|
||||
val targetAccount = intent.getStringExtra(Intent.EXTRA_USER)
|
||||
|
||||
if (targetAccount != null && !currentUser.nameEquals(targetAccount)) {
|
||||
val targetUser = userAccountManager.getUser(targetAccount)
|
||||
if (targetUser.isPresent) {
|
||||
setUser(targetUser.get())
|
||||
} else {
|
||||
Toast.makeText(this, R.string.associated_account_not_found, Toast.LENGTH_LONG).show()
|
||||
finish()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
clientFactory?.let {
|
||||
val trashRepository = RemoteTrashbinRepository(user.orElse(accountProvider!!.user), it)
|
||||
trashbinPresenter = TrashbinPresenter(trashRepository, this)
|
||||
}
|
||||
|
||||
binding = TrashbinActivityBinding.inflate(layoutInflater)
|
||||
|
||||
setContentView(binding.root)
|
||||
setupToolbar()
|
||||
|
||||
findViewById<View>(R.id.sort_list_button_group).visibility = View.VISIBLE
|
||||
findViewById<View>(R.id.switch_grid_view_button).visibility =
|
||||
View.GONE
|
||||
|
||||
updateActionBarTitleAndHomeButtonByString(getString(R.string.trashbin_activity_title))
|
||||
setupDrawer(R.id.nav_trashbin)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
|
||||
active = true
|
||||
setupContent()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
setDrawerMenuItemChecked(R.id.nav_trashbin)
|
||||
}
|
||||
|
||||
private fun setupContent() {
|
||||
val recyclerView = binding.list
|
||||
recyclerView.setEmptyView(binding.emptyList.emptyListView)
|
||||
|
||||
binding.emptyList.emptyListView.visibility = View.GONE
|
||||
binding.emptyList.emptyListIcon.setImageResource(R.drawable.ic_delete)
|
||||
binding.emptyList.emptyListIcon.visibility = View.VISIBLE
|
||||
binding.emptyList.emptyListViewHeadline.text = getString(R.string.trashbin_empty_headline)
|
||||
binding.emptyList.emptyListViewText.text = getString(R.string.trashbin_empty_message)
|
||||
binding.emptyList.emptyListViewText.visibility = View.VISIBLE
|
||||
|
||||
trashbinListAdapter = TrashbinListAdapter(
|
||||
this,
|
||||
storageManager,
|
||||
preferences,
|
||||
this,
|
||||
user.orElse(accountProvider!!.user),
|
||||
viewThemeUtils
|
||||
)
|
||||
|
||||
recyclerView.adapter = trashbinListAdapter
|
||||
recyclerView.setHasFixedSize(true)
|
||||
recyclerView.setHasFooter(true)
|
||||
recyclerView.layoutManager = LinearLayoutManager(this)
|
||||
|
||||
viewThemeUtils.androidx.themeSwipeRefreshLayout(binding.swipeContainingList)
|
||||
binding.swipeContainingList.setOnRefreshListener { loadFolder() }
|
||||
viewThemeUtils.material.colorMaterialTextButton(findViewById(R.id.sort_button))
|
||||
|
||||
findViewById<View>(R.id.sort_button).setOnClickListener {
|
||||
DisplayUtils.openSortingOrderDialogFragment(
|
||||
supportFragmentManager,
|
||||
preferences?.getSortOrderByType(
|
||||
FileSortOrder.Type.trashBinView,
|
||||
FileSortOrder.sort_new_to_old
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
loadFolder()
|
||||
|
||||
handleOnBackPressed()
|
||||
}
|
||||
|
||||
private fun handleOnBackPressed() {
|
||||
onBackPressedDispatcher.addCallback(
|
||||
this,
|
||||
object : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() {
|
||||
trashbinPresenter?.navigateUp()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun loadFolder() {
|
||||
trashbinListAdapter?.let {
|
||||
if (it.itemCount > EMPTY_LIST_COUNT) {
|
||||
binding.swipeContainingList.isRefreshing = true
|
||||
} else {
|
||||
showInitialLoading()
|
||||
}
|
||||
|
||||
trashbinPresenter?.loadFolder()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
var retval = true
|
||||
val itemId = item.itemId
|
||||
if (itemId == android.R.id.home) {
|
||||
if (isDrawerOpen) {
|
||||
closeDrawer()
|
||||
} else if (trashbinPresenter?.isRoot == true) {
|
||||
trashbinPresenter?.navigateUp()
|
||||
} else {
|
||||
openDrawer()
|
||||
}
|
||||
} else if (itemId == R.id.action_empty_trashbin) {
|
||||
trashbinPresenter?.emptyTrashbin()
|
||||
} else {
|
||||
retval = super.onOptionsItemSelected(item)
|
||||
}
|
||||
return retval
|
||||
}
|
||||
|
||||
override fun onOverflowIconClicked(file: TrashbinFile, view: View) {
|
||||
val popup = PopupMenu(this, view)
|
||||
popup.inflate(R.menu.item_trashbin)
|
||||
popup.setOnMenuItemClickListener {
|
||||
trashbinPresenter?.removeTrashbinFile(file)
|
||||
true
|
||||
}
|
||||
popup.show()
|
||||
}
|
||||
|
||||
override fun onItemClicked(file: TrashbinFile) {
|
||||
if (file.isFolder) {
|
||||
trashbinPresenter?.enterFolder(file.remotePath)
|
||||
mDrawerToggle.isDrawerIndicatorEnabled = false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRestoreIconClicked(file: TrashbinFile, view: View) {
|
||||
trashbinPresenter?.restoreTrashbinFile(file)
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
menuInflater.inflate(R.menu.activity_trashbin, menu)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
active = false
|
||||
trashbinListAdapter?.cancelAllPendingTasks()
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
trashbinPresenter?.navigateUp()
|
||||
}
|
||||
|
||||
override fun setDrawerIndicatorEnabled(bool: Boolean) {
|
||||
mDrawerToggle.isDrawerIndicatorEnabled = bool
|
||||
}
|
||||
|
||||
override fun onSortingOrderChosen(sortOrder: FileSortOrder?) {
|
||||
val sortButton = findViewById<TextView>(R.id.sort_button)
|
||||
sortButton.setText(DisplayUtils.getSortOrderStringId(sortOrder))
|
||||
trashbinListAdapter?.setSortOrder(sortOrder)
|
||||
}
|
||||
|
||||
override fun showTrashbinFolder(trashbinFiles: List<TrashbinFile?>?) {
|
||||
if (active) {
|
||||
trashbinListAdapter?.setTrashbinFiles(trashbinFiles, true)
|
||||
binding.swipeContainingList.isRefreshing = false
|
||||
binding.loadingContent.visibility = View.GONE
|
||||
binding.emptyList.emptyListIcon.setImageResource(R.drawable.ic_delete)
|
||||
binding.emptyList.emptyListViewHeadline.text = getString(R.string.trashbin_empty_headline)
|
||||
binding.emptyList.emptyListViewText.text = getString(R.string.trashbin_empty_message)
|
||||
binding.list.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
override fun removeFile(file: TrashbinFile?) {
|
||||
if (active) {
|
||||
trashbinListAdapter?.removeFile(file)
|
||||
}
|
||||
}
|
||||
|
||||
override fun removeAllFiles() {
|
||||
trashbinListAdapter?.removeAllFiles()
|
||||
}
|
||||
|
||||
override fun showSnackbarError(message: Int, file: TrashbinFile?) {
|
||||
if (active) {
|
||||
binding.swipeContainingList.isRefreshing = false
|
||||
Snackbar.make(binding.list, String.format(getString(message), file?.fileName), Snackbar.LENGTH_LONG)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
fun showInitialLoading() {
|
||||
binding.emptyList.emptyListView.visibility = View.GONE
|
||||
binding.list.visibility = View.GONE
|
||||
binding.loadingContent.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
fun showUser() {
|
||||
binding.loadingContent.visibility = View.GONE
|
||||
binding.list.visibility = View.VISIBLE
|
||||
binding.swipeContainingList.isRefreshing = false
|
||||
binding.emptyList.emptyListViewText.text = user.get().accountName
|
||||
binding.emptyList.emptyListViewText.visibility = View.VISIBLE
|
||||
binding.emptyList.emptyListView.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
override fun showError(message: Int) {
|
||||
if (active) {
|
||||
trashbinListAdapter?.removeAllFiles()
|
||||
binding.loadingContent.visibility = View.GONE
|
||||
binding.list.visibility = View.VISIBLE
|
||||
binding.swipeContainingList.isRefreshing = false
|
||||
binding.emptyList.emptyListViewHeadline.setText(R.string.common_error)
|
||||
binding.emptyList.emptyListIcon.setImageDrawable(
|
||||
ResourcesCompat.getDrawable(
|
||||
resources,
|
||||
R.drawable.ic_list_empty_error,
|
||||
null
|
||||
)
|
||||
)
|
||||
binding.emptyList.emptyListViewText.setText(message)
|
||||
binding.emptyList.emptyListViewText.visibility = View.VISIBLE
|
||||
binding.emptyList.emptyListIcon.visibility = View.VISIBLE
|
||||
binding.emptyList.emptyListView.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val EMPTY_LIST_COUNT = 1
|
||||
}
|
||||
}
|
|
@ -18,47 +18,31 @@
|
|||
* 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.trashbin;
|
||||
package com.owncloud.android.ui.trashbin
|
||||
|
||||
import com.owncloud.android.lib.resources.trashbin.model.TrashbinFile;
|
||||
|
||||
import java.util.List;
|
||||
import com.owncloud.android.lib.resources.trashbin.model.TrashbinFile
|
||||
|
||||
/**
|
||||
* Contract between view (TrashbinActivity) and presenter (TrashbinPresenter)
|
||||
*/
|
||||
public interface TrashbinContract {
|
||||
|
||||
interface TrashbinContract {
|
||||
interface View {
|
||||
void showTrashbinFolder(List<TrashbinFile> trashbinFiles);
|
||||
|
||||
void showSnackbarError(int message, TrashbinFile file);
|
||||
|
||||
void showError(int message);
|
||||
|
||||
void removeFile(TrashbinFile file);
|
||||
|
||||
void removeAllFiles();
|
||||
|
||||
void close();
|
||||
|
||||
void setDrawerIndicatorEnabled(boolean bool);
|
||||
fun showTrashbinFolder(trashbinFiles: List<TrashbinFile?>?)
|
||||
fun showSnackbarError(message: Int, file: TrashbinFile?)
|
||||
fun showError(message: Int)
|
||||
fun removeFile(file: TrashbinFile?)
|
||||
fun removeAllFiles()
|
||||
fun close()
|
||||
fun setDrawerIndicatorEnabled(bool: Boolean)
|
||||
}
|
||||
|
||||
interface Presenter {
|
||||
|
||||
boolean isRoot();
|
||||
|
||||
void loadFolder();
|
||||
|
||||
void navigateUp();
|
||||
|
||||
void enterFolder(String folder);
|
||||
|
||||
void restoreTrashbinFile(TrashbinFile file);
|
||||
|
||||
void removeTrashbinFile(TrashbinFile file);
|
||||
|
||||
void emptyTrashbin();
|
||||
val isRoot: Boolean
|
||||
fun loadFolder()
|
||||
fun navigateUp()
|
||||
fun enterFolder(folder: String?)
|
||||
fun restoreTrashbinFile(file: TrashbinFile?)
|
||||
fun removeTrashbinFile(file: TrashbinFile?)
|
||||
fun emptyTrashbin()
|
||||
}
|
||||
}
|
|
@ -1,116 +0,0 @@
|
|||
/*
|
||||
* 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.trashbin;
|
||||
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.lib.resources.trashbin.model.TrashbinFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
import static com.owncloud.android.datamodel.OCFile.ROOT_PATH;
|
||||
|
||||
/**
|
||||
* Coordinates between model and view: querying model, updating view, react to UI input
|
||||
*/
|
||||
public class TrashbinPresenter implements TrashbinContract.Presenter {
|
||||
|
||||
private TrashbinContract.View trashbinView;
|
||||
private TrashbinRepository trashbinRepository;
|
||||
private String currentPath = ROOT_PATH;
|
||||
|
||||
public TrashbinPresenter(TrashbinRepository trashbinRepository, TrashbinContract.View trashbinView) {
|
||||
this.trashbinRepository = trashbinRepository;
|
||||
this.trashbinView = trashbinView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterFolder(String folder) {
|
||||
currentPath = folder;
|
||||
loadFolder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRoot() {
|
||||
return !ROOT_PATH.equals(currentPath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void navigateUp() {
|
||||
if (ROOT_PATH.equals(currentPath)) {
|
||||
trashbinView.close();
|
||||
} else {
|
||||
currentPath = new File(currentPath).getParent();
|
||||
|
||||
loadFolder();
|
||||
}
|
||||
|
||||
trashbinView.setDrawerIndicatorEnabled(ROOT_PATH.equals(currentPath));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadFolder() {
|
||||
trashbinRepository.getFolder(currentPath, new TrashbinRepository.LoadFolderCallback() {
|
||||
@Override
|
||||
public void onSuccess(List<TrashbinFile> files) {
|
||||
trashbinView.showTrashbinFolder(files);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int error) {
|
||||
trashbinView.showError(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreTrashbinFile(TrashbinFile file) {
|
||||
trashbinRepository.restoreFile(file, success -> {
|
||||
if (success) {
|
||||
trashbinView.removeFile(file);
|
||||
} else {
|
||||
trashbinView.showSnackbarError(R.string.trashbin_file_not_restored, file);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeTrashbinFile(TrashbinFile file) {
|
||||
trashbinRepository.removeTrashbinFile(file, success -> {
|
||||
if (success) {
|
||||
trashbinView.removeFile(file);
|
||||
} else {
|
||||
trashbinView.showSnackbarError(R.string.trashbin_file_not_deleted, file);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emptyTrashbin() {
|
||||
trashbinRepository.emptyTrashbin(success -> {
|
||||
if (success) {
|
||||
trashbinView.removeAllFiles();
|
||||
} else {
|
||||
trashbinView.showError(R.string.trashbin_not_emptied);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* 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.trashbin
|
||||
|
||||
import com.owncloud.android.R
|
||||
import com.owncloud.android.datamodel.OCFile
|
||||
import com.owncloud.android.lib.resources.trashbin.model.TrashbinFile
|
||||
import com.owncloud.android.ui.trashbin.TrashbinContract.Presenter
|
||||
import com.owncloud.android.ui.trashbin.TrashbinRepository.LoadFolderCallback
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* Coordinates between model and view: querying model, updating view, react to UI input
|
||||
*/
|
||||
class TrashbinPresenter(
|
||||
private val trashbinRepository: TrashbinRepository,
|
||||
private val trashbinView: TrashbinContract.View
|
||||
) : Presenter {
|
||||
|
||||
private var currentPath: String? = OCFile.ROOT_PATH
|
||||
|
||||
override fun enterFolder(folder: String?) {
|
||||
currentPath = folder
|
||||
loadFolder()
|
||||
}
|
||||
|
||||
override val isRoot: Boolean
|
||||
get() = OCFile.ROOT_PATH != currentPath
|
||||
|
||||
override fun navigateUp() {
|
||||
if (OCFile.ROOT_PATH == currentPath) {
|
||||
trashbinView.close()
|
||||
} else {
|
||||
currentPath?.let {
|
||||
currentPath = File(it).parent
|
||||
loadFolder()
|
||||
}
|
||||
}
|
||||
|
||||
trashbinView.setDrawerIndicatorEnabled(OCFile.ROOT_PATH == currentPath)
|
||||
}
|
||||
|
||||
override fun loadFolder() {
|
||||
trashbinRepository.getFolder(
|
||||
currentPath,
|
||||
object : LoadFolderCallback {
|
||||
override fun onSuccess(files: List<TrashbinFile?>?) {
|
||||
trashbinView.showTrashbinFolder(files)
|
||||
}
|
||||
|
||||
override fun onError(error: Int) {
|
||||
trashbinView.showError(error)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun restoreTrashbinFile(file: TrashbinFile?) {
|
||||
trashbinRepository.restoreFile(
|
||||
file,
|
||||
object : TrashbinRepository.OperationCallback {
|
||||
override fun onResult(success: Boolean) {
|
||||
if (success) {
|
||||
trashbinView.removeFile(file)
|
||||
} else {
|
||||
trashbinView.showSnackbarError(R.string.trashbin_file_not_restored, file)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun removeTrashbinFile(file: TrashbinFile?) {
|
||||
trashbinRepository.removeTrashbinFile(
|
||||
file,
|
||||
object : TrashbinRepository.OperationCallback {
|
||||
override fun onResult(success: Boolean) {
|
||||
if (success) {
|
||||
trashbinView.removeFile(file)
|
||||
} else {
|
||||
trashbinView.showSnackbarError(R.string.trashbin_file_not_deleted, file)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun emptyTrashbin() {
|
||||
trashbinRepository.emptyTrashbin(object : TrashbinRepository.OperationCallback {
|
||||
override fun onResult(success: Boolean) {
|
||||
if (success) {
|
||||
trashbinView.removeAllFiles()
|
||||
} else {
|
||||
trashbinView.showError(R.string.trashbin_not_emptied)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -18,31 +18,25 @@
|
|||
* 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.trashbin;
|
||||
package com.owncloud.android.ui.trashbin
|
||||
|
||||
import com.owncloud.android.lib.resources.trashbin.model.TrashbinFile;
|
||||
|
||||
import java.util.List;
|
||||
import com.owncloud.android.lib.resources.trashbin.model.TrashbinFile
|
||||
|
||||
/**
|
||||
* Contract between presenter and model
|
||||
*/
|
||||
public interface TrashbinRepository {
|
||||
interface TrashbinRepository {
|
||||
interface LoadFolderCallback {
|
||||
void onSuccess(List<TrashbinFile> files);
|
||||
|
||||
void onError(int error);
|
||||
fun onSuccess(files: List<TrashbinFile?>?)
|
||||
fun onError(error: Int)
|
||||
}
|
||||
|
||||
interface OperationCallback {
|
||||
void onResult(boolean success);
|
||||
fun onResult(success: Boolean)
|
||||
}
|
||||
|
||||
void getFolder(String remotePath, LoadFolderCallback callback);
|
||||
|
||||
void restoreFile(TrashbinFile file, OperationCallback callback);
|
||||
|
||||
void emptyTrashbin(OperationCallback callback);
|
||||
|
||||
void removeTrashbinFile(TrashbinFile file, OperationCallback callback);
|
||||
fun getFolder(remotePath: String?, callback: LoadFolderCallback?)
|
||||
fun restoreFile(file: TrashbinFile?, callback: OperationCallback?)
|
||||
fun emptyTrashbin(callback: OperationCallback?)
|
||||
fun removeTrashbinFile(file: TrashbinFile?, callback: OperationCallback?)
|
||||
}
|
|
@ -1,2 +1,2 @@
|
|||
DO NOT TOUCH; GENERATED BY DRONE
|
||||
<span class="mdl-layout-title">Lint Report: 77 warnings</span>
|
||||
<span class="mdl-layout-title">Lint Report: 75 warnings</span>
|
||||
|
|
Loading…
Reference in a new issue