mirror of
https://github.com/nextcloud/android.git
synced 2024-11-27 17:46:37 +03:00
Merge pull request #2690 from nextcloud/comments
Iteration 5 for File detail & new sharing - Comments
This commit is contained in:
commit
dc315a9394
7 changed files with 269 additions and 18 deletions
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* 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.google.gson.GsonBuilder;
|
||||
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.commons.httpclient.methods.PostMethod;
|
||||
import org.apache.commons.httpclient.methods.StringRequestEntity;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* Restore a {@link com.owncloud.android.lib.resources.files.FileVersion}.
|
||||
*/
|
||||
public class CommentFileOperation extends SyncOperation {
|
||||
|
||||
private static final String TAG = CommentFileOperation.class.getSimpleName();
|
||||
private static final int POST_READ_TIMEOUT = 30000;
|
||||
private static final int POST_CONNECTION_TIMEOUT = 5000;
|
||||
|
||||
private static final String ACTOR_ID = "actorId";
|
||||
private static final String ACTOR_TYPE = "actorType";
|
||||
private static final String ACTOR_TYPE_VALUE = "users";
|
||||
private static final String VERB = "verb";
|
||||
private static final String VERB_VALUE = "comment";
|
||||
private static final String MESSAGE = "message";
|
||||
|
||||
private String message;
|
||||
private String fileId;
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param message Comment to store
|
||||
* @param userId userId to access correct dav endpoint
|
||||
*/
|
||||
public CommentFileOperation(String message, String fileId, String userId) {
|
||||
this.message = message;
|
||||
this.fileId = fileId;
|
||||
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 url = client.getNewWebdavUri(false) + "/comments/files/" + fileId;
|
||||
PostMethod postMethod = new PostMethod(url);
|
||||
postMethod.addRequestHeader("Content-type", "application/json");
|
||||
|
||||
Map<String, String> values = new HashMap<>();
|
||||
values.put(ACTOR_ID, userId);
|
||||
values.put(ACTOR_TYPE, ACTOR_TYPE_VALUE);
|
||||
values.put(VERB, VERB_VALUE);
|
||||
values.put(MESSAGE, message);
|
||||
|
||||
String json = new GsonBuilder().create().toJson(values, Map.class);
|
||||
|
||||
postMethod.setRequestEntity(new StringRequestEntity(json));
|
||||
|
||||
int status = client.executeMethod(postMethod, POST_READ_TIMEOUT, POST_CONNECTION_TIMEOUT);
|
||||
|
||||
result = new RemoteOperationResult(isSuccess(status), postMethod);
|
||||
|
||||
client.exhaustResponse(postMethod.getResponseBodyAsStream());
|
||||
} catch (IOException e) {
|
||||
result = new RemoteOperationResult(e);
|
||||
Log.e(TAG, "Post comment to file with id " + fileId + " failed: " + result.getLogMessage(), e);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean isSuccess(int status) {
|
||||
return status == HttpStatus.SC_CREATED;
|
||||
}
|
||||
}
|
|
@ -26,8 +26,11 @@ 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.design.widget.TextInputEditText;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.support.v4.widget.SwipeRefreshLayout;
|
||||
|
@ -57,6 +60,7 @@ 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.CommentFileOperation;
|
||||
import com.owncloud.android.ui.activity.ComponentsGetter;
|
||||
import com.owncloud.android.ui.activity.FileActivity;
|
||||
import com.owncloud.android.ui.adapter.ActivityAndVersionListAdapter;
|
||||
|
@ -71,6 +75,7 @@ import java.util.ArrayList;
|
|||
import butterknife.BindString;
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.OnClick;
|
||||
import butterknife.Unbinder;
|
||||
|
||||
public class FileDetailActivitiesFragment extends Fragment implements ActivityListInterface, VersionListInterface.View {
|
||||
|
@ -113,14 +118,19 @@ public class FileDetailActivitiesFragment extends Fragment implements ActivityLi
|
|||
@BindView(android.R.id.list)
|
||||
public RecyclerView recyclerView;
|
||||
|
||||
@BindView(R.id.commentInputField)
|
||||
public TextInputEditText commentInput;
|
||||
|
||||
@BindString(R.string.activities_no_results_headline)
|
||||
public String noResultsHeadline;
|
||||
|
||||
@BindString(R.string.activities_no_results_message)
|
||||
public String noResultsMessage;
|
||||
|
||||
private boolean restoreFileVersionSupported;
|
||||
private String userId;
|
||||
private FileOperationsHelper operationsHelper;
|
||||
private VersionListInterface.CommentCallback callback;
|
||||
|
||||
public static FileDetailActivitiesFragment newInstance(OCFile file, Account account) {
|
||||
FileDetailActivitiesFragment fragment = new FileDetailActivitiesFragment();
|
||||
|
@ -154,19 +164,43 @@ public class FileDetailActivitiesFragment extends Fragment implements ActivityLi
|
|||
|
||||
fetchAndSetData(null);
|
||||
|
||||
swipeListRefreshLayout.setOnRefreshListener(
|
||||
() -> onRefreshListLayout(swipeListRefreshLayout));
|
||||
swipeEmptyListRefreshLayout.setOnRefreshListener(
|
||||
() -> onRefreshListLayout(swipeEmptyListRefreshLayout));
|
||||
swipeListRefreshLayout.setOnRefreshListener(() -> onRefreshListLayout(swipeListRefreshLayout));
|
||||
swipeEmptyListRefreshLayout.setOnRefreshListener(() -> onRefreshListLayout(swipeEmptyListRefreshLayout));
|
||||
|
||||
AccountManager accountManager = AccountManager.get(getContext());
|
||||
userId = accountManager.getUserData(account,
|
||||
com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_USER_ID);
|
||||
|
||||
callback = new VersionListInterface.CommentCallback() {
|
||||
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
commentInput.getText().clear();
|
||||
fetchAndSetData(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int error) {
|
||||
Snackbar.make(recyclerView, error, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
};
|
||||
|
||||
commentInput.getBackground().setColorFilter(
|
||||
ThemeUtils.primaryAccentColor(getContext()),
|
||||
PorterDuff.Mode.SRC_ATOP
|
||||
);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@OnClick(R.id.submitComment)
|
||||
public void submitComment() {
|
||||
if (commentInput.getText().toString().trim().length() > 0) {
|
||||
new SubmitCommentTask(commentInput.getText().toString(), userId, file.getLocalId(),
|
||||
callback, ownCloudClient).execute();
|
||||
}
|
||||
}
|
||||
|
||||
private void onRefreshListLayout(SwipeRefreshLayout refreshLayout) {
|
||||
setLoadingMessage();
|
||||
if (refreshLayout != null && refreshLayout.isRefreshing()) {
|
||||
|
@ -389,4 +423,43 @@ public class FileDetailActivitiesFragment extends Fragment implements ActivityLi
|
|||
public void onRestoreClicked(FileVersion fileVersion) {
|
||||
operationsHelper.restoreFileVersion(fileVersion, userId);
|
||||
}
|
||||
}
|
||||
|
||||
private static class SubmitCommentTask extends AsyncTask<Void, Void, Boolean> {
|
||||
|
||||
private String message;
|
||||
private String userId;
|
||||
private String fileId;
|
||||
private VersionListInterface.CommentCallback callback;
|
||||
private OwnCloudClient client;
|
||||
|
||||
private SubmitCommentTask(String message, String userId, String fileId,
|
||||
VersionListInterface.CommentCallback callback, OwnCloudClient client) {
|
||||
this.message = message;
|
||||
this.userId = userId;
|
||||
this.fileId = fileId;
|
||||
this.callback = callback;
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... voids) {
|
||||
CommentFileOperation commentFileOperation = new CommentFileOperation(message, fileId, userId);
|
||||
|
||||
RemoteOperationResult result = commentFileOperation.execute(client);
|
||||
|
||||
return result.isSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean success) {
|
||||
super.onPostExecute(success);
|
||||
|
||||
if (success) {
|
||||
callback.onSuccess();
|
||||
} else {
|
||||
callback.onError(R.string.error_comment_file);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -60,7 +60,7 @@ public class FileFragment extends Fragment {
|
|||
super.onCreate(savedInstanceState);
|
||||
|
||||
Bundle bundle = getArguments();
|
||||
setFile((OCFile) bundle.getParcelable(EXTRA_FILE));
|
||||
setFile(bundle.getParcelable(EXTRA_FILE));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -28,4 +28,10 @@ public interface VersionListInterface {
|
|||
interface View {
|
||||
void onRestoreClicked(FileVersion fileVersion);
|
||||
}
|
||||
|
||||
interface CommentCallback {
|
||||
void onSuccess();
|
||||
|
||||
void onError(int error);
|
||||
}
|
||||
}
|
||||
|
|
25
src/main/res/drawable/ic_send.xml
Normal file
25
src/main/res/drawable/ic_send.xml
Normal file
|
@ -0,0 +1,25 @@
|
|||
<!--
|
||||
@author Google LLC
|
||||
Copyright (C) 2018 Google LLC
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24"
|
||||
android:viewportWidth="24">
|
||||
<path
|
||||
android:fillColor="#757575"
|
||||
android:pathData="M2,21L23,12L2,3V10L17,12L2,14V21Z" />
|
||||
</vector>
|
|
@ -18,36 +18,69 @@
|
|||
License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent">
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/zero"
|
||||
android:layout_marginLeft="@dimen/standard_padding"
|
||||
android:layout_marginRight="@dimen/zero"
|
||||
android:layout_marginStart="@dimen/standard_padding"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<android.support.design.widget.TextInputEditText
|
||||
android:id="@+id/commentInputField"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:hint="@string/new_comment"
|
||||
android:paddingTop="@dimen/standard_padding" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/submitComment"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/common_send"
|
||||
android:paddingBottom="@dimen/standard_padding"
|
||||
android:paddingEnd="@dimen/standard_padding"
|
||||
android:paddingLeft="@dimen/standard_padding"
|
||||
android:paddingRight="@dimen/standard_padding"
|
||||
android:paddingStart="@dimen/standard_padding"
|
||||
android:paddingTop="@dimen/standard_padding"
|
||||
android:src="@drawable/ic_send" />
|
||||
</LinearLayout>
|
||||
|
||||
<android.support.v4.widget.SwipeRefreshLayout
|
||||
android:footerDividersEnabled="false"
|
||||
android:id="@+id/swipe_containing_list"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:footerDividersEnabled="false"
|
||||
android:visibility="visible">
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:clipToPadding="false"
|
||||
android:id="@android:id/list"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:scrollbarStyle="outsideOverlay"
|
||||
android:scrollbars="vertical"
|
||||
android:visibility="visible" />
|
||||
android:visibility="visible"/>
|
||||
|
||||
</android.support.v4.widget.SwipeRefreshLayout>
|
||||
|
||||
<android.support.v4.widget.SwipeRefreshLayout
|
||||
android:footerDividersEnabled="false"
|
||||
android:id="@+id/swipe_containing_empty"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:footerDividersEnabled="false"
|
||||
android:visibility="visible">
|
||||
|
||||
<include layout="@layout/empty_list" />
|
||||
<include layout="@layout/empty_list"/>
|
||||
</android.support.v4.widget.SwipeRefreshLayout>
|
||||
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
|
|
|
@ -800,6 +800,8 @@
|
|||
<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="new_comment">New comment…</string>
|
||||
<string name="error_comment_file">Error commenting file</string>
|
||||
<string name="file_version_restored_successfully">Successfully restored file version.</string>
|
||||
<string name="file_version_restored_error">Error restoring file version!</string>
|
||||
<string name="outdated_server">The server has reached end of life, please upgrade!</string>
|
||||
|
|
Loading…
Reference in a new issue