Added ability to read comments on claims (#920)

* Added ability to read comments on claims
* Added simple handling for pagination in CommentListTask
This commit is contained in:
Clayton Hickey 2020-05-29 19:47:50 -04:00 committed by GitHub
parent a40c160ac6
commit dcc91f75cc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 364 additions and 12 deletions

View file

@ -0,0 +1,52 @@
package io.lbry.browser.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.List;
import androidx.recyclerview.widget.RecyclerView;
import io.lbry.browser.R;
import io.lbry.browser.model.Comment;
public class CommentListAdapter extends RecyclerView.Adapter<CommentListAdapter.ViewHolder> {
private List<Comment> items;
private Context context;
public CommentListAdapter(List<Comment> items, Context context) {
this.items = items;
this.context = context;
}
@Override
public int getItemCount() {
return items != null ? items.size() : 0;
}
public static class ViewHolder extends RecyclerView.ViewHolder {
protected TextView channelName;
protected TextView commentText;
public ViewHolder (View v) {
super(v);
channelName = v.findViewById(R.id.comment_channel_name);
commentText = v.findViewById(R.id.comment_text);
}
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(context).inflate(R.layout.list_item_comment, parent, false);
return new CommentListAdapter.ViewHolder(v);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Comment comment = items.get(position);
holder.channelName.setText(comment.getChannelName());
holder.commentText.setText(comment.getText());
}
}

View file

@ -0,0 +1,40 @@
package io.lbry.browser.model;
import android.util.Log;
import org.json.JSONException;
import org.json.JSONObject;
import lombok.Data;
@Data
public class Comment {
private final String channelName, text, id, parentId;
public Comment(String channelName, String text, String id, String parentId) {
this.channelName = channelName;
this.text = text;
this.id = id;
this.parentId = parentId;
}
public static Comment fromJSONObject(JSONObject jsonObject) {
try {
String parentId = null;
if (jsonObject.has("parent_id")) {
parentId = jsonObject.getString("parent_id");
}
return new Comment(
jsonObject.getString("channel_name"),
jsonObject.getString("comment"),
jsonObject.getString("comment_id"),
parentId
);
} catch (JSONException ex) {
// TODO: Throw exception
Log.e("Comments", ex.toString());
return null;
}
}
}

View file

@ -0,0 +1,10 @@
package io.lbry.browser.tasks;
import java.util.List;
import io.lbry.browser.model.Comment;
public interface CommentListHandler {
void onSuccess(List<Comment> comments);
void onError(Exception error);
}

View file

@ -0,0 +1,77 @@
package io.lbry.browser.tasks;
import android.os.AsyncTask;
import android.view.View;
import android.widget.ProgressBar;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import io.lbry.browser.model.Comment;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry;
public class CommentListTask extends AsyncTask<Void, Void, List<Comment>> {
private final int page;
private final int pageSize;
private final String claim;
private ProgressBar progressBar;
private CommentListHandler handler;
private Exception error;
public CommentListTask(int page, int pageSize, String claim, ProgressBar progressBar, CommentListHandler handler) {
this.page = page;
this.pageSize = pageSize;
this.claim = claim;
this.progressBar = progressBar;
this.handler = handler;
}
protected void onPreExecute() {
Helper.setViewVisibility(progressBar, View.VISIBLE);
}
protected List<Comment> doInBackground(Void... voids) {
List<Comment> comments = null;
try {
Map<String, Object> options = new HashMap<>();
options.put("claim_id", claim);
options.put("page", page);
options.put("page_size", pageSize);
options.put("include_replies", false);
options.put("is_channel_signature_valid", true);
options.put("visible", true);
options.put("hidden", false);
JSONObject result = (JSONObject) Lbry.genericApiCall(Lbry.METHOD_COMMENT_LIST, options);
JSONArray items = result.getJSONArray("items");
comments = new ArrayList<>();
for (int i = 0; i < items.length(); i++) {
comments.add(Comment.fromJSONObject(items.getJSONObject(i)));
}
} catch (Exception ex) {
error = ex;
}
return comments;
}
protected void onPostExecute(List<Comment> comments) {
Helper.setViewVisibility(progressBar, View.GONE);
if (handler != null) {
if (comments != null && error == null) {
handler.onSuccess(comments);
} else {
handler.onError(error);
if (error != null) {
}
}
}
}
}

View file

@ -89,6 +89,7 @@ import java.util.concurrent.TimeUnit;
import io.lbry.browser.MainActivity; import io.lbry.browser.MainActivity;
import io.lbry.browser.R; import io.lbry.browser.R;
import io.lbry.browser.adapter.ClaimListAdapter; import io.lbry.browser.adapter.ClaimListAdapter;
import io.lbry.browser.adapter.CommentListAdapter;
import io.lbry.browser.adapter.TagListAdapter; import io.lbry.browser.adapter.TagListAdapter;
import io.lbry.browser.dialog.RepostClaimDialogFragment; import io.lbry.browser.dialog.RepostClaimDialogFragment;
import io.lbry.browser.dialog.SendTipDialogFragment; import io.lbry.browser.dialog.SendTipDialogFragment;
@ -102,6 +103,7 @@ import io.lbry.browser.listener.StoragePermissionListener;
import io.lbry.browser.listener.WalletBalanceListener; import io.lbry.browser.listener.WalletBalanceListener;
import io.lbry.browser.model.Claim; import io.lbry.browser.model.Claim;
import io.lbry.browser.model.ClaimCacheKey; import io.lbry.browser.model.ClaimCacheKey;
import io.lbry.browser.model.Comment;
import io.lbry.browser.model.Fee; import io.lbry.browser.model.Fee;
import io.lbry.browser.model.LbryFile; import io.lbry.browser.model.LbryFile;
import io.lbry.browser.model.NavMenuItem; import io.lbry.browser.model.NavMenuItem;
@ -110,6 +112,8 @@ import io.lbry.browser.model.UrlSuggestion;
import io.lbry.browser.model.WalletBalance; import io.lbry.browser.model.WalletBalance;
import io.lbry.browser.model.lbryinc.Reward; import io.lbry.browser.model.lbryinc.Reward;
import io.lbry.browser.model.lbryinc.Subscription; import io.lbry.browser.model.lbryinc.Subscription;
import io.lbry.browser.tasks.CommentListHandler;
import io.lbry.browser.tasks.CommentListTask;
import io.lbry.browser.tasks.GenericTaskHandler; import io.lbry.browser.tasks.GenericTaskHandler;
import io.lbry.browser.tasks.LighthouseSearchTask; import io.lbry.browser.tasks.LighthouseSearchTask;
import io.lbry.browser.tasks.ReadTextFileTask; import io.lbry.browser.tasks.ReadTextFileTask;
@ -164,6 +168,7 @@ public class FileViewFragment extends BaseFragment implements
private Claim claim; private Claim claim;
private String currentUrl; private String currentUrl;
private ClaimListAdapter relatedContentAdapter; private ClaimListAdapter relatedContentAdapter;
private CommentListAdapter commentListAdapter;
private BroadcastReceiver sdkReceiver; private BroadcastReceiver sdkReceiver;
private Player.EventListener fileViewPlayerListener; private Player.EventListener fileViewPlayerListener;
@ -317,6 +322,7 @@ public class FileViewFragment extends BaseFragment implements
if (claim != null) { if (claim != null) {
Helper.saveViewHistory(currentUrl, claim); Helper.saveViewHistory(currentUrl, claim);
checkAndLoadRelatedContent(); checkAndLoadRelatedContent();
checkAndLoadComments();
renderClaim(); renderClaim();
if (claim.getFile() == null) { if (claim.getFile() == null) {
loadFile(); loadFile();
@ -451,6 +457,7 @@ public class FileViewFragment extends BaseFragment implements
loadFile(); loadFile();
} }
checkOwnClaim(); checkOwnClaim();
checkAndLoadComments();
} }
private String getStreamingUrl() { private String getStreamingUrl() {
@ -532,6 +539,7 @@ public class FileViewFragment extends BaseFragment implements
if (claim != null) { if (claim != null) {
Helper.saveViewHistory(url, claim); Helper.saveViewHistory(url, claim);
checkAndLoadRelatedContent(); checkAndLoadRelatedContent();
checkAndLoadComments();
renderClaim(); renderClaim();
} }
} }
@ -571,7 +579,7 @@ public class FileViewFragment extends BaseFragment implements
loadAndScheduleDurations(); loadAndScheduleDurations();
} }
if (Lbry.SDK_READY) { if (!Lbry.SDK_READY) {
if (context instanceof MainActivity) { if (context instanceof MainActivity) {
((MainActivity) context).addSdkStatusListener(this); ((MainActivity) context).addSdkStatusListener(this);
} }
@ -652,6 +660,7 @@ public class FileViewFragment extends BaseFragment implements
loadFile(); loadFile();
checkAndLoadRelatedContent(); checkAndLoadRelatedContent();
checkAndLoadComments();
renderClaim(); renderClaim();
} else { } else {
// render nothing at location // render nothing at location
@ -989,9 +998,13 @@ public class FileViewFragment extends BaseFragment implements
}); });
RecyclerView relatedContentList = root.findViewById(R.id.file_view_related_content_list); RecyclerView relatedContentList = root.findViewById(R.id.file_view_related_content_list);
RecyclerView commentsList = root.findViewById(R.id.file_view_comments_list);
relatedContentList.setNestedScrollingEnabled(false); relatedContentList.setNestedScrollingEnabled(false);
LinearLayoutManager llm = new LinearLayoutManager(getContext()); commentsList.setNestedScrollingEnabled(false);
relatedContentList.setLayoutManager(llm); LinearLayoutManager relatedContentListLLM = new LinearLayoutManager(getContext());
LinearLayoutManager commentsListLLM = new LinearLayoutManager(getContext());
relatedContentList.setLayoutManager(relatedContentListLLM);
commentsList.setLayoutManager(commentsListLLM);
} }
private void deleteCurrentClaim() { private void deleteCurrentClaim() {
@ -1317,6 +1330,22 @@ public class FileViewFragment extends BaseFragment implements
} }
} }
private void checkAndLoadComments() {
View root = getView();
if (root != null) {
RecyclerView commentsList = root.findViewById(R.id.file_view_comments_list);
if (commentsList == null || commentsList.getAdapter() == null || commentsList.getAdapter().getItemCount() == 0) {
TextView commentsSDKInitializing = root.findViewById(R.id.file_view_comments_sdk_initializing);
if (Lbry.SDK_READY) {
Helper.setViewVisibility(commentsSDKInitializing, View.GONE);
loadComments();
} else {
Helper.setViewVisibility(commentsSDKInitializing, View.VISIBLE);
}
}
}
}
private void showUnsupportedView() { private void showUnsupportedView() {
View root = getView(); View root = getView();
if (root != null) { if (root != null) {
@ -1856,6 +1885,39 @@ public class FileViewFragment extends BaseFragment implements
} }
} }
private void loadComments() {
View root = getView();
ProgressBar relatedLoading = root.findViewById(R.id.file_view_comments_progress);
if (claim != null && root != null) {
CommentListTask relatedTask = new CommentListTask(1, 999, claim.getClaimId(), relatedLoading, new CommentListHandler() {
@Override
public void onSuccess(List<Comment> comments) {
Context ctx = getContext();
if (ctx != null) {
commentListAdapter = new CommentListAdapter(comments, ctx);
View v = getView();
if (v != null) {
RecyclerView relatedContentList = root.findViewById(R.id.file_view_comments_list);
relatedContentList.setAdapter(commentListAdapter);
commentListAdapter.notifyDataSetChanged();
Helper.setViewVisibility(
v.findViewById(R.id.file_view_no_comments),
commentListAdapter == null || commentListAdapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
}
}
}
@Override
public void onError(Exception error) {
}
});
relatedTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
public boolean onBackPressed() { public boolean onBackPressed() {
if (isInFullscreenMode()) { if (isInFullscreenMode()) {
disableFullScreenMode(); disableFullScreenMode();

View file

@ -102,6 +102,8 @@ public final class Lbry {
public static final String METHOD_STREAM_ABANDON = "stream_abandon"; public static final String METHOD_STREAM_ABANDON = "stream_abandon";
public static final String METHOD_STREAM_REPOST = "stream_repost"; public static final String METHOD_STREAM_REPOST = "stream_repost";
public static final String METHOD_COMMENT_LIST = "comment_list";
public static KeyStore KEYSTORE; public static KeyStore KEYSTORE;
public static boolean SDK_READY = false; public static boolean SDK_READY = false;

View file

@ -480,23 +480,24 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="16dp" android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"> android:layout_marginRight="16dp">
<LinearLayout <LinearLayout
android:id="@+id/file_view_publisher_name_area" android:id="@+id/file_view_publisher_name_area"
android:clickable="true"
android:orientation="vertical"
android:layout_centerVertical="true"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content"
android:clickable="true"
android:orientation="vertical">
<TextView <TextView
android:id="@+id/file_view_publisher_name" android:id="@+id/file_view_publisher_name"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textSize="14sp" android:background="?attr/selectableItemBackground"
android:textColor="@color/lbryGreen" android:clickable="true"
android:fontFamily="@font/inter" android:fontFamily="@font/inter"
android:textFontWeight="600" /> android:textColor="@color/lbryGreen"
android:textFontWeight="600"
android:textSize="14sp" />
</LinearLayout> </LinearLayout>
<io.lbry.browser.ui.controls.SolidIconView <io.lbry.browser.ui.controls.SolidIconView
android:id="@+id/file_view_icon_follow_unfollow" android:id="@+id/file_view_icon_follow_unfollow"
@ -611,6 +612,75 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
</LinearLayout> </LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_marginBottom="12dp"
android:background="@color/divider" />
<LinearLayout
android:id="@+id/file_view_comments_area"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="8dp"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp">
<ProgressBar
android:id="@+id/file_view_comments_progress"
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:visibility="gone" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:fontFamily="@font/inter"
android:text="@string/comments"
android:textSize="16sp" />
</RelativeLayout>
<TextView
android:id="@+id/file_view_no_comments"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="8dp"
android:fontFamily="@font/inter"
android:text="@string/no_comments"
android:textFontWeight="300"
android:textSize="14sp"
android:visibility="gone" />
<TextView
android:id="@+id/file_view_comments_sdk_initializing"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="8dp"
android:fontFamily="@font/inter"
android:text="@string/sdk_initializing_comments"
android:textFontWeight="300"
android:textSize="14sp"
android:visibility="gone" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/file_view_comments_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:overScrollMode="never" />
</LinearLayout>
</LinearLayout> </LinearLayout>
</androidx.core.widget.NestedScrollView> </androidx.core.widget.NestedScrollView>
</LinearLayout> </LinearLayout>

View file

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:orientation="vertical"
android:paddingBottom="8dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="8dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/comment_channel_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/inter"
android:text="channel_name"
android:textColor="@color/lbryGreen"
android:textSize="14sp" />
<TextView
android:id="@+id/comment_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/inter"
android:text="comment_text" />
</LinearLayout>
</LinearLayout>

View file

@ -59,6 +59,9 @@
<string name="report">Report</string> <string name="report">Report</string>
<string name="loading_decentralized_data">Loading decentralized data...</string> <string name="loading_decentralized_data">Loading decentralized data...</string>
<string name="related_content">Related Content</string> <string name="related_content">Related Content</string>
<string name="comments">Comments</string>
<string name="no_comments">No comments to display.</string>
<string name="sdk_initializing_comments">Comments will display once the background service is done initializing.</string>
<string name="share_lbry_content">Share LBRY content</string> <string name="share_lbry_content">Share LBRY content</string>
<string name="view">View</string> <string name="view">View</string>
<string name="play">Play</string> <string name="play">Play</string>