mirror of
https://github.com/nextcloud/android.git
synced 2024-11-22 13:15:35 +03:00
Add file version to activity stream
Signed-off-by: tobiasKaminsky <tobias@kaminsky.me>
This commit is contained in:
parent
941ab7c023
commit
075b0f52b8
15 changed files with 523 additions and 108 deletions
|
@ -206,9 +206,9 @@ dependencies {
|
|||
// dependencies for app building
|
||||
implementation 'com.android.support:multidex:1.0.3'
|
||||
// implementation project('nextcloud-android-library')
|
||||
genericImplementation "com.github.nextcloud:android-library:master-SNAPSHOT"
|
||||
gplayImplementation "com.github.nextcloud:android-library:master-SNAPSHOT"
|
||||
versionDevImplementation 'com.github.nextcloud:android-library:master-SNAPSHOT' // use always latest master
|
||||
genericImplementation "com.github.nextcloud:android-library:fileVersioning-SNAPSHOT"
|
||||
gplayImplementation "com.github.nextcloud:android-library:fileVersioning-SNAPSHOT"
|
||||
versionDevImplementation 'com.github.nextcloud:android-library:fileVersioning-SNAPSHOT' // use always latest master
|
||||
implementation "com.android.support:support-v4:${supportLibraryVersion}"
|
||||
implementation "com.android.support:design:${supportLibraryVersion}"
|
||||
implementation 'com.jakewharton:disklrucache:2.0.2'
|
||||
|
|
4
drawable_resources/ic_history.svg
Normal file
4
drawable_resources/ic_history.svg
Normal file
|
@ -0,0 +1,4 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewbox="0 0 16 16" width="16" height="16">
|
||||
<path
|
||||
d="m9.025 1.08c-3.95 0-6.535 3.447-6.364 6.72h-2.161l3.904 3.92 4.08-3.874h-2.147c-0.237-1.7 1.163-3.114 2.689-3.092 1.595 0.024 2.8 1.23 2.8 2.734 0.09 1.594-1.63 3.428-3.966 2.53 0 1.23 0.003 2.545 0 3.765 4.19 0.83 7.64-2.51 7.64-6.25 0-3.563-2.92-6.453-6.475-6.453z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 396 B |
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* 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.operations;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.owncloud.android.lib.common.OwnCloudClient;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import com.owncloud.android.operations.common.SyncOperation;
|
||||
|
||||
import org.apache.commons.httpclient.HttpStatus;
|
||||
import org.apache.jackrabbit.webdav.client.methods.MoveMethod;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
/**
|
||||
* Restore a {@link com.owncloud.android.lib.resources.files.FileVersion}.
|
||||
*/
|
||||
public class RestoreFileVersionOperation extends SyncOperation {
|
||||
|
||||
private static final String TAG = RestoreFileVersionOperation.class.getSimpleName();
|
||||
private static final int RESTORE_READ_TIMEOUT = 30000;
|
||||
private static final int RESTORE_CONNECTION_TIMEOUT = 5000;
|
||||
|
||||
private String fileId;
|
||||
private String fileName;
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param fileId fileId
|
||||
* @param fileName version date in unixtime
|
||||
* @param userId userId to access correct dav endpoint
|
||||
*/
|
||||
public RestoreFileVersionOperation(String fileId, String fileName, String userId) {
|
||||
this.fileId = fileId;
|
||||
this.fileName = fileName;
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the operation.
|
||||
*
|
||||
* @param client Client object to communicate with the remote ownCloud server.
|
||||
*/
|
||||
@Override
|
||||
protected RemoteOperationResult run(OwnCloudClient client) {
|
||||
|
||||
RemoteOperationResult result;
|
||||
try {
|
||||
String source = client.getNewWebdavUri(false) + "/versions/" + userId + "/versions/" + fileId + "/" + fileName;
|
||||
String target = client.getNewWebdavUri(false) + "/versions/" + userId + "/restore/" + fileId;
|
||||
|
||||
MoveMethod move = new MoveMethod(source, target, true);
|
||||
int status = client.executeMethod(move, RESTORE_READ_TIMEOUT, RESTORE_CONNECTION_TIMEOUT);
|
||||
|
||||
result = new RemoteOperationResult(isSuccess(status), move);
|
||||
|
||||
client.exhaustResponse(move.getResponseBodyAsStream());
|
||||
} catch (IOException e) {
|
||||
result = new RemoteOperationResult(e);
|
||||
Log.e(TAG, "Restore file version with id " + fileId + " failed: " + result.getLogMessage(), e);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean isSuccess(int status) {
|
||||
return status == HttpStatus.SC_CREATED || status == HttpStatus.SC_NO_CONTENT;
|
||||
}
|
||||
}
|
|
@ -36,7 +36,6 @@ import android.widget.ProgressBar;
|
|||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.datamodel.FileDataStorageManager;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.datamodel.ThumbnailsCacheManager;
|
||||
import com.owncloud.android.utils.ThemeUtils;
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,162 @@
|
|||
package com.owncloud.android.ui.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.text.format.DateFormat;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.datamodel.FileDataStorageManager;
|
||||
import com.owncloud.android.lib.resources.activities.models.Activity;
|
||||
import com.owncloud.android.lib.resources.files.FileVersion;
|
||||
import com.owncloud.android.ui.interfaces.ActivityListInterface;
|
||||
import com.owncloud.android.ui.interfaces.VersionListInterface;
|
||||
import com.owncloud.android.utils.DisplayUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
|
||||
public class ActivityAndVersionListAdapter extends ActivityListAdapter {
|
||||
|
||||
private static final int VERSION_TYPE = 102;
|
||||
private VersionListInterface.View versionListInterface;
|
||||
|
||||
public ActivityAndVersionListAdapter(Context context, ActivityListInterface activityListInterface,
|
||||
VersionListInterface.View versionListInterface,
|
||||
FileDataStorageManager storageManager) {
|
||||
super(context, activityListInterface, storageManager);
|
||||
|
||||
this.versionListInterface = versionListInterface;
|
||||
}
|
||||
|
||||
public void setActivityAndVersionItems(ArrayList<Object> items, boolean clear) {
|
||||
if (clear) {
|
||||
mValues.clear();
|
||||
Collections.sort(items, (o1, o2) -> {
|
||||
long o1Date;
|
||||
long o2Date;
|
||||
if (o1 instanceof Activity) {
|
||||
o1Date = ((Activity) o1).datetime.getTime();
|
||||
} else {
|
||||
o1Date = ((FileVersion) o1).getModifiedTimestamp();
|
||||
}
|
||||
|
||||
if (o2 instanceof Activity) {
|
||||
o2Date = ((Activity) o2).datetime.getTime();
|
||||
} else {
|
||||
o2Date = ((FileVersion) o2).getModifiedTimestamp();
|
||||
}
|
||||
|
||||
return -1 * Long.compare(o1Date, o2Date);
|
||||
});
|
||||
}
|
||||
|
||||
String sTime = "";
|
||||
for (Object item : items) {
|
||||
String time;
|
||||
|
||||
if (item instanceof Activity) {
|
||||
Activity activity = (Activity) item;
|
||||
if (activity.getDatetime() != null) {
|
||||
time = getHeaderDateString(context, activity.getDatetime().getTime()).toString();
|
||||
} else if (activity.getDate() != null) {
|
||||
time = getHeaderDateString(context, activity.getDate().getTime()).toString();
|
||||
} else {
|
||||
time = context.getString(R.string.date_unknown);
|
||||
}
|
||||
} else {
|
||||
FileVersion version = (FileVersion) item;
|
||||
time = getHeaderDateString(context, version.getModifiedTimestamp()).toString();
|
||||
}
|
||||
|
||||
if (sTime.equalsIgnoreCase(time)) {
|
||||
mValues.add(item);
|
||||
} else {
|
||||
sTime = time;
|
||||
mValues.add(sTime);
|
||||
mValues.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
switch (viewType) {
|
||||
case VERSION_TYPE:
|
||||
View versionView = LayoutInflater.from(parent.getContext()).inflate(R.layout.version_list_item,
|
||||
parent, false);
|
||||
return new VersionViewHolder(versionView);
|
||||
default:
|
||||
return super.onCreateViewHolder(parent, viewType);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
|
||||
if (holder instanceof VersionViewHolder) {
|
||||
final VersionViewHolder versionViewHolder = (VersionViewHolder) holder;
|
||||
FileVersion fileVersion = (FileVersion) mValues.get(position);
|
||||
|
||||
versionViewHolder.size.setText(DisplayUtils.bytesToHumanReadable(fileVersion.getFileLength()));
|
||||
versionViewHolder.time.setText(DateFormat.format("HH:mm", new Date(fileVersion.getModifiedTimestamp())
|
||||
.getTime()));
|
||||
|
||||
versionViewHolder.restore.setOnClickListener(v -> versionListInterface.onRestoreClicked(fileVersion,
|
||||
new VersionListInterface.Callback() {
|
||||
@Override
|
||||
public void onSuccess(FileVersion fileVersion) {
|
||||
versionListInterface.onSuccess(context.getString(
|
||||
R.string.file_version_restored_successfully));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String error) {
|
||||
|
||||
}
|
||||
}));
|
||||
} else {
|
||||
super.onBindViewHolder(holder, position);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
Object value = mValues.get(position);
|
||||
|
||||
if (value instanceof Activity)
|
||||
return ACTIVITY_TYPE;
|
||||
else if (value instanceof FileVersion) {
|
||||
return VERSION_TYPE;
|
||||
} else {
|
||||
return HEADER_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
protected class VersionViewHolder extends RecyclerView.ViewHolder {
|
||||
@BindView(R.id.thumbnail)
|
||||
public ImageView thumbnail;
|
||||
@BindView(R.id.size)
|
||||
public TextView size;
|
||||
@BindView(R.id.time)
|
||||
public TextView time;
|
||||
@BindView(R.id.restore)
|
||||
public ImageView restore;
|
||||
|
||||
VersionViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
ButterKnife.bind(this, itemView);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@ import android.content.res.Resources;
|
|||
import android.graphics.Color;
|
||||
import android.graphics.drawable.PictureDrawable;
|
||||
import android.net.Uri;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableStringBuilder;
|
||||
|
@ -77,16 +78,16 @@ import java.util.List;
|
|||
|
||||
public class ActivityListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||
|
||||
private static final int HEADER_TYPE = 100;
|
||||
private static final int ACTIVITY_TYPE = 101;
|
||||
private final ActivityListInterface activityListInterface;
|
||||
protected static final int HEADER_TYPE = 100;
|
||||
protected static final int ACTIVITY_TYPE = 101;
|
||||
protected final ActivityListInterface activityListInterface;
|
||||
private final int px;
|
||||
private static final String TAG = ActivityListAdapter.class.getSimpleName();
|
||||
private OwnCloudClient mClient;
|
||||
|
||||
private Context context;
|
||||
protected Context context;
|
||||
private FileDataStorageManager storageManager;
|
||||
private List<Object> mValues;
|
||||
protected List<Object> mValues;
|
||||
|
||||
public ActivityListAdapter(Context context, ActivityListInterface activityListInterface,
|
||||
FileDataStorageManager storageManager) {
|
||||
|
@ -127,8 +128,9 @@ public class ActivityListAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
|
|||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
if (viewType == ACTIVITY_TYPE) {
|
||||
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.activity_list_item, parent, false);
|
||||
return new ActivityViewHolder(v);
|
||||
|
@ -136,12 +138,10 @@ public class ActivityListAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
|
|||
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.activity_list_item_header, parent, false);
|
||||
return new ActivityViewHeaderHolder(v);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
|
||||
|
||||
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
|
||||
if (holder instanceof ActivityViewHolder) {
|
||||
final ActivityViewHolder activityViewHolder = (ActivityViewHolder) holder;
|
||||
Activity activity = (Activity) mValues.get(position);
|
||||
|
@ -354,7 +354,7 @@ public class ActivityListAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
|
|||
return d.intValue();
|
||||
}
|
||||
|
||||
private CharSequence getHeaderDateString(Context context, long modificationTimestamp) {
|
||||
protected CharSequence getHeaderDateString(Context context, long modificationTimestamp) {
|
||||
if ((System.currentTimeMillis() - modificationTimestamp) < DateUtils.WEEK_IN_MILLIS) {
|
||||
return DisplayUtils.getRelativeDateTimeString(context, modificationTimestamp, DateUtils.DAY_IN_MILLIS,
|
||||
DateUtils.WEEK_IN_MILLIS, 0);
|
||||
|
@ -363,7 +363,7 @@ public class ActivityListAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
|
|||
}
|
||||
}
|
||||
|
||||
private class ActivityViewHolder extends RecyclerView.ViewHolder {
|
||||
protected class ActivityViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private final ImageView activityIcon;
|
||||
private final TextView subject;
|
||||
|
@ -371,7 +371,7 @@ public class ActivityListAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
|
|||
private final TextView dateTime;
|
||||
private final GridLayout list;
|
||||
|
||||
private ActivityViewHolder(View itemView) {
|
||||
protected ActivityViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
activityIcon = itemView.findViewById(R.id.activity_icon);
|
||||
subject = itemView.findViewById(R.id.activity_subject);
|
||||
|
@ -381,11 +381,11 @@ public class ActivityListAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
|
|||
}
|
||||
}
|
||||
|
||||
private class ActivityViewHeaderHolder extends RecyclerView.ViewHolder {
|
||||
protected class ActivityViewHeaderHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private final TextView title;
|
||||
|
||||
private ActivityViewHeaderHolder(View itemView) {
|
||||
protected ActivityViewHeaderHolder(View itemView) {
|
||||
super(itemView);
|
||||
title = itemView.findViewById(R.id.title_header);
|
||||
|
||||
|
|
|
@ -50,14 +50,12 @@ import com.owncloud.android.ui.dialog.ExpirationDatePickerDialogFragment;
|
|||
import com.owncloud.android.ui.fragment.util.SharingMenuHelper;
|
||||
import com.owncloud.android.utils.DisplayUtils;
|
||||
import com.owncloud.android.utils.ThemeUtils;
|
||||
import com.owncloud.android.utils.DisplayUtils;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.List;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Adapter to show a user/group/email/remote in Sharing list in file details view.
|
||||
|
@ -379,23 +377,6 @@ public class UserListAdapter extends RecyclerView.Adapter<UserListAdapter.UserVi
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void avatarGenerated(Drawable avatarDrawable, Object callContext) {
|
||||
if (callContext instanceof ImageView) {
|
||||
ImageView iv = (ImageView) callContext;
|
||||
iv.setImageDrawable(avatarDrawable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldCallGeneratedCallback(String tag, Object callContext) {
|
||||
if (callContext instanceof ImageView) {
|
||||
ImageView iv = (ImageView) callContext;
|
||||
return String.valueOf(iv.getTag()).equals(tag);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public interface ShareeListAdapterListener {
|
||||
/**
|
||||
* unshare with given sharee {@link OCShare}.
|
||||
|
|
|
@ -21,12 +21,15 @@
|
|||
package com.owncloud.android.ui.fragment;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.accounts.AuthenticatorException;
|
||||
import android.accounts.OperationCanceledException;
|
||||
import android.content.Context;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.support.v4.widget.SwipeRefreshLayout;
|
||||
|
@ -52,27 +55,32 @@ import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
|||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.lib.resources.activities.GetRemoteActivitiesOperation;
|
||||
import com.owncloud.android.lib.resources.activities.models.RichObject;
|
||||
import com.owncloud.android.lib.resources.files.FileVersion;
|
||||
import com.owncloud.android.lib.resources.files.ReadFileVersionsOperation;
|
||||
import com.owncloud.android.lib.resources.status.OCCapability;
|
||||
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
|
||||
import com.owncloud.android.operations.RestoreFileVersionOperation;
|
||||
import com.owncloud.android.ui.activity.FileActivity;
|
||||
import com.owncloud.android.ui.adapter.ActivityListAdapter;
|
||||
import com.owncloud.android.ui.adapter.ActivityAndVersionListAdapter;
|
||||
import com.owncloud.android.ui.interfaces.ActivityListInterface;
|
||||
import com.owncloud.android.ui.interfaces.VersionListInterface;
|
||||
import com.owncloud.android.utils.ThemeUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import butterknife.BindString;
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.Unbinder;
|
||||
|
||||
public class FileDetailActivitiesFragment extends Fragment implements ActivityListInterface {
|
||||
public class FileDetailActivitiesFragment extends Fragment implements ActivityListInterface, VersionListInterface.View {
|
||||
private static final String TAG = FileDetailActivitiesFragment.class.getSimpleName();
|
||||
|
||||
private static final String ARG_FILE = "FILE";
|
||||
private static final String ARG_ACCOUNT = "ACCOUNT";
|
||||
|
||||
private ActivityListAdapter adapter;
|
||||
private ActivityAndVersionListAdapter adapter;
|
||||
private Unbinder unbinder;
|
||||
private OwnCloudClient ownCloudClient;
|
||||
|
||||
|
@ -111,6 +119,8 @@ public class FileDetailActivitiesFragment extends Fragment implements ActivityLi
|
|||
|
||||
@BindString(R.string.activities_no_results_message)
|
||||
public String noResultsMessage;
|
||||
private boolean restoreFileVersionSupported;
|
||||
private String userId;
|
||||
|
||||
public static FileDetailActivitiesFragment newInstance(OCFile file, Account account) {
|
||||
FileDetailActivitiesFragment fragment = new FileDetailActivitiesFragment();
|
||||
|
@ -149,6 +159,11 @@ public class FileDetailActivitiesFragment extends Fragment implements ActivityLi
|
|||
swipeEmptyListRefreshLayout.setOnRefreshListener(
|
||||
() -> onRefreshListLayout(swipeEmptyListRefreshLayout));
|
||||
|
||||
AccountManager accountManager = AccountManager.get(getContext());
|
||||
userId = accountManager.getUserData(account,
|
||||
com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_USER_ID);
|
||||
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
|
@ -175,11 +190,17 @@ public class FileDetailActivitiesFragment extends Fragment implements ActivityLi
|
|||
|
||||
private void setupView() {
|
||||
FileDataStorageManager storageManager = new FileDataStorageManager(account, getActivity().getContentResolver());
|
||||
|
||||
OCCapability capability = storageManager.getCapability(account.name);
|
||||
OwnCloudVersion serverVersion = AccountUtils.getServerVersion(account);
|
||||
restoreFileVersionSupported = capability.getFilesVersioning().isTrue() &&
|
||||
serverVersion.compareTo(OwnCloudVersion.nextcloud_14) >= 0;
|
||||
|
||||
emptyContentProgressBar.getIndeterminateDrawable().setColorFilter(ThemeUtils.primaryAccentColor(getContext()),
|
||||
PorterDuff.Mode.SRC_IN);
|
||||
emptyContentIcon.setImageDrawable(getResources().getDrawable(R.drawable.ic_activity_light_grey));
|
||||
|
||||
adapter = new ActivityListAdapter(getContext(), this, storageManager);
|
||||
adapter = new ActivityAndVersionListAdapter(getContext(), this, this, storageManager);
|
||||
recyclerView.setAdapter(adapter);
|
||||
|
||||
LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
|
||||
|
@ -228,7 +249,7 @@ public class FileDetailActivitiesFragment extends Fragment implements ActivityLi
|
|||
|
||||
GetRemoteActivitiesOperation getRemoteNotificationOperation = new GetRemoteActivitiesOperation(
|
||||
file.getLocalId());
|
||||
|
||||
|
||||
if (pageUrl != null) {
|
||||
getRemoteNotificationOperation.setNextUrl(pageUrl);
|
||||
}
|
||||
|
@ -236,14 +257,28 @@ public class FileDetailActivitiesFragment extends Fragment implements ActivityLi
|
|||
Log_OC.d(TAG, "BEFORE getRemoteActivitiesOperation.execute");
|
||||
final RemoteOperationResult result = getRemoteNotificationOperation.execute(ownCloudClient);
|
||||
|
||||
ArrayList<Object> versions = null;
|
||||
if (restoreFileVersionSupported) {
|
||||
ReadFileVersionsOperation readFileVersionsOperation = new ReadFileVersionsOperation(file.getLocalId(),
|
||||
userId);
|
||||
|
||||
RemoteOperationResult result1 = readFileVersionsOperation.execute(ownCloudClient);
|
||||
|
||||
versions = result1.getData();
|
||||
}
|
||||
|
||||
if (result.isSuccess() && result.getData() != null) {
|
||||
final ArrayList<Object> data = result.getData();
|
||||
final ArrayList<Object> activities = (ArrayList) data.get(0);
|
||||
final ArrayList<Object> activitiesAndVersions = (ArrayList) data.get(0);
|
||||
|
||||
if (restoreFileVersionSupported && versions != null) {
|
||||
activitiesAndVersions.addAll(versions);
|
||||
}
|
||||
nextPageUrl = (String) data.get(1);
|
||||
|
||||
activity.runOnUiThread(() -> {
|
||||
populateList(activities, ownCloudClient, pageUrl == null);
|
||||
if (activities.isEmpty()) {
|
||||
populateList(activitiesAndVersions, pageUrl == null);
|
||||
if (activitiesAndVersions.isEmpty()) {
|
||||
setEmptyContent(noResultsHeadline, noResultsMessage);
|
||||
list.setVisibility(View.GONE);
|
||||
empty.setVisibility(View.VISIBLE);
|
||||
|
@ -283,8 +318,8 @@ public class FileDetailActivitiesFragment extends Fragment implements ActivityLi
|
|||
t.start();
|
||||
}
|
||||
|
||||
private void populateList(List<Object> activities, OwnCloudClient mClient, boolean clear) {
|
||||
adapter.setActivityItems(activities, mClient, clear);
|
||||
private void populateList(ArrayList<Object> activities, boolean clear) {
|
||||
adapter.setActivityAndVersionItems(activities, clear);
|
||||
}
|
||||
|
||||
private void setEmptyContent(String headline, String message) {
|
||||
|
@ -344,4 +379,60 @@ public class FileDetailActivitiesFragment extends Fragment implements ActivityLi
|
|||
outState.putParcelable(FileActivity.EXTRA_FILE, file);
|
||||
outState.putParcelable(FileActivity.EXTRA_ACCOUNT, account);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(String message) {
|
||||
Snackbar.make(recyclerView, message, Snackbar.LENGTH_LONG).show();
|
||||
fetchAndSetData(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestoreClicked(FileVersion fileVersion, VersionListInterface.Callback callback) {
|
||||
new RestoreFileVersionTask(fileVersion, userId, ownCloudClient, callback).execute();
|
||||
}
|
||||
|
||||
// TODO extract according to MVP, will be in following PR
|
||||
private static class RestoreFileVersionTask extends AsyncTask<Void, Void, Boolean> {
|
||||
|
||||
private FileVersion file;
|
||||
private String userId;
|
||||
private OwnCloudClient client;
|
||||
private VersionListInterface.Callback callback;
|
||||
|
||||
private RestoreFileVersionTask(FileVersion file, String userId, OwnCloudClient client,
|
||||
VersionListInterface.Callback callback) {
|
||||
this.file = file;
|
||||
this.userId = userId;
|
||||
this.client = client;
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... voids) {
|
||||
|
||||
RestoreFileVersionOperation restoreFileVersionOperation = new RestoreFileVersionOperation(
|
||||
file.getRemoteId(), file.getFileName(), userId);
|
||||
|
||||
RemoteOperationResult result = restoreFileVersionOperation.execute(client);
|
||||
|
||||
return result.isSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean success) {
|
||||
super.onPostExecute(success);
|
||||
|
||||
if (success) {
|
||||
callback.onSuccess(file);
|
||||
} else {
|
||||
callback.onError("error");
|
||||
|
||||
}
|
||||
|
||||
// TODO refactor to MVP
|
||||
// if true, delete old local copy && update file list
|
||||
|
||||
// callback.onResult(success);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -38,7 +38,6 @@ import android.view.View.OnClickListener;
|
|||
import android.view.ViewGroup;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.PopupMenu;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
@ -68,10 +67,6 @@ import java.lang.ref.WeakReference;
|
|||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.Unbinder;
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.Optional;
|
||||
import butterknife.Unbinder;
|
||||
|
||||
/**
|
||||
* This Fragment is used to display the details about a file.
|
||||
|
@ -128,60 +123,6 @@ public class FileDetailFragment extends FileFragment implements OnClickListener
|
|||
private ToolbarActivity activity;
|
||||
private int activeTab;
|
||||
|
||||
@Nullable @BindView(R.id.fdProgressBlock)
|
||||
View downloadProgressContainer;
|
||||
|
||||
@Nullable @BindView(R.id.fdCancelBtn)
|
||||
ImageButton cancelButton;
|
||||
|
||||
@Nullable @BindView(R.id.fdProgressBar)
|
||||
ProgressBar progressBar;
|
||||
|
||||
@Nullable @BindView(R.id.fdProgressText)
|
||||
TextView progressText;
|
||||
|
||||
@Nullable @BindView(R.id.fdFilename)
|
||||
TextView fileName;
|
||||
|
||||
@Nullable @BindView(R.id.fdSize)
|
||||
TextView fileSize;
|
||||
|
||||
@Nullable @BindView(R.id.fdModified)
|
||||
TextView fileModifiedTimestamp;
|
||||
|
||||
@Nullable @BindView(R.id.fdFavorite)
|
||||
ImageView favoriteIcon;
|
||||
|
||||
@Nullable @BindView(R.id.overflow_menu)
|
||||
ImageView overflowMenu;
|
||||
|
||||
@Nullable @BindView(R.id.tab_layout)
|
||||
TabLayout tabLayout;
|
||||
|
||||
@Nullable @BindView(R.id.pager)
|
||||
ViewPager viewPager;
|
||||
|
||||
@Nullable @BindView(R.id.empty_list_view_text)
|
||||
protected TextView emptyContentMessage;
|
||||
|
||||
@Nullable @BindView(R.id.empty_list_view_headline)
|
||||
protected TextView emptyContentHeadline;
|
||||
|
||||
@Nullable @BindView(R.id.empty_list_icon)
|
||||
protected ImageView emptyContentIcon;
|
||||
|
||||
@Nullable @BindView(R.id.empty_list_progress)
|
||||
protected ProgressBar emptyProgressBar;
|
||||
|
||||
private int layout;
|
||||
private View view;
|
||||
private boolean previewLoaded;
|
||||
private Account account;
|
||||
private Unbinder unbinder;
|
||||
|
||||
public ProgressListener progressListener;
|
||||
private ToolbarActivity activity;
|
||||
|
||||
/**
|
||||
* Public factory method to create new FileDetailFragment instances.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* 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.interfaces;
|
||||
|
||||
import com.owncloud.android.lib.resources.files.FileVersion;
|
||||
|
||||
public interface VersionListInterface {
|
||||
|
||||
interface View {
|
||||
void onRestoreClicked(FileVersion fileVersion, Callback callback);
|
||||
|
||||
void onSuccess(String message);
|
||||
}
|
||||
|
||||
interface Callback {
|
||||
void onSuccess(FileVersion fileVersion);
|
||||
|
||||
void onError(String error);
|
||||
}
|
||||
}
|
|
@ -34,7 +34,9 @@ import com.owncloud.android.lib.common.utils.Log_OC;
|
|||
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
|
|
11
src/main/res/drawable/ic_history.xml
Normal file
11
src/main/res/drawable/ic_history.xml
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M9.025 1.08c-3.95 0-6.535 3.447-6.364 6.72h-2.161l3.904 3.92 4.08-3.874h-2.147c-0.237-1.7 1.163-3.114 2.689-3.092 1.595 0.024 2.8 1.23 2.8 2.734 0.09 1.594-1.63 3.428-3.966 2.53 0 1.23 0.003 2.545 0 3.765 4.19 0.83 7.64-2.51 7.64-6.25 0-3.563-2.92-6.453-6.475-6.453z"/>
|
||||
</vector>
|
87
src/main/res/layout/version_list_item.xml
Normal file
87
src/main/res/layout/version_list_item.xml
Normal file
|
@ -0,0 +1,87 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
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/>.
|
||||
-->
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="@dimen/standard_padding"
|
||||
android:paddingRight="@dimen/standard_padding"
|
||||
android:paddingBottom="@dimen/standard_padding"
|
||||
android:paddingLeft="@dimen/standard_padding">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/thumbnail"
|
||||
android:layout_width="@dimen/activity_icon_width"
|
||||
android:layout_height="@dimen/activity_icon_height"
|
||||
android:layout_marginEnd="@dimen/activity_icon_layout_right_end_margin"
|
||||
android:layout_marginRight="@dimen/activity_icon_layout_right_end_margin"
|
||||
android:alpha="0.5"
|
||||
android:contentDescription="@string/thumbnail"
|
||||
android:src="@drawable/ic_activity"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/version_created"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:text="@string/new_version_was_created"
|
||||
android:textAppearance="?android:attr/textAppearanceListItem"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/size"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:ellipsize="end"
|
||||
android:text="@string/placeholder_sentence"
|
||||
android:textColor="?android:attr/textColorSecondary"/>
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/restore"
|
||||
android:layout_width="@dimen/restore_icon_width"
|
||||
android:layout_height="@dimen/restore_icon_height"
|
||||
android:layout_marginEnd="@dimen/restore_icon_layout_right_end_margin"
|
||||
android:layout_marginRight="@dimen/restore_icon_layout_right_end_margin"
|
||||
android:layout_weight="1"
|
||||
android:alpha="0.5"
|
||||
android:contentDescription="@string/restore"
|
||||
android:src="@drawable/ic_history"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:layout_weight="1"
|
||||
android:ellipsize="end"
|
||||
android:text="@string/placeholder_sentence"
|
||||
android:textColor="?android:attr/textColorSecondary"/>
|
||||
|
||||
</LinearLayout>
|
|
@ -88,6 +88,9 @@
|
|||
<dimen name="media_grid_spacing">2dp</dimen>
|
||||
<dimen name="account_item_layout_user_image_left_start_margin">12dp</dimen>
|
||||
<dimen name="account_item_layout_user_image_margin">1dp</dimen>
|
||||
<dimen name="restore_icon_width">24dp</dimen>
|
||||
<dimen name="restore_icon_height">24dp</dimen>
|
||||
<dimen name="restore_icon_layout_right_end_margin">24dp</dimen>
|
||||
<dimen name="activity_icon_width">32dp</dimen>
|
||||
<dimen name="activity_icon_height">32dp</dimen>
|
||||
<dimen name="activity_icon_layout_right_end_margin">24dp</dimen>
|
||||
|
|
|
@ -797,4 +797,7 @@
|
|||
<string name="updating_share_failed">Updating share failed</string>
|
||||
<string name="whats_new_device_credentials_title">Use Android device protection</string>
|
||||
<string name="whats_new_device_credentials_content">Use anything like a pattern, password, pin or your fingerprint to keep your data safe.</string>
|
||||
<string name="restore">Restore file</string>
|
||||
<string name="new_version_was_created">New version was created</string>
|
||||
<string name="file_version_restored_successfully">Successfully restored file version.</string>
|
||||
</resources>
|
||||
|
|
Loading…
Reference in a new issue