package me.ccrama.redditslide.Activities;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.Html;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.afollestad.materialdialogs.AlertDialogWrapper;
import com.afollestad.materialdialogs.MaterialDialog;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.neovisionaries.ws.client.WebSocketException;
import com.neovisionaries.ws.client.WebSocketFactory;
import com.neovisionaries.ws.client.WebSocketFrame;
import com.neovisionaries.ws.client.WebSocketListener;
import com.neovisionaries.ws.client.WebSocketState;
import net.dean.jraw.managers.LiveThreadManager;
import net.dean.jraw.models.LiveUpdate;
import net.dean.jraw.paginators.LiveThreadPaginator;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import me.ccrama.redditslide.Authentication;
import me.ccrama.redditslide.ContentType;
import me.ccrama.redditslide.R;
import me.ccrama.redditslide.Reddit;
import me.ccrama.redditslide.SpoilerRobotoTextView;
import me.ccrama.redditslide.TimeUtils;
import me.ccrama.redditslide.Views.CommentOverflow;
import me.ccrama.redditslide.Views.SidebarLayout;
import me.ccrama.redditslide.Visuals.Palette;
import me.ccrama.redditslide.util.HttpUtil;
import me.ccrama.redditslide.util.LogUtil;
import me.ccrama.redditslide.util.SubmissionParser;
import me.ccrama.redditslide.util.TwitterObject;
import okhttp3.OkHttpClient;
public class LiveThread extends BaseActivityAnim {
public static final String EXTRA_LIVEURL = "liveurl";
public net.dean.jraw.models.LiveThread thread;
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
onBackPressed();
return true;
case R.id.info:
((DrawerLayout) findViewById(R.id.drawer_layout)).openDrawer(Gravity.RIGHT);
return true;
default:
return false;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.settings_info, menu);
return true;
}
public RecyclerView baseRecycler;
public String term;
@Override
public void onDestroy() {
super.onDestroy();
//todo finish
}
@Override
public void onCreate(Bundle savedInstanceState) {
overrideSwipeFromAnywhere();
getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
getWindow().getDecorView().setBackgroundDrawable(null);
super.onCreate(savedInstanceState);
applyColorTheme();
setContentView(R.layout.activity_livethread);
baseRecycler = (RecyclerView) findViewById(R.id.content_view);
baseRecycler.setLayoutManager(new LinearLayoutManager(LiveThread.this));
new AsyncTask<Void, Void, Void>() {
MaterialDialog d;
@Override
public void onPreExecute() {
d = new MaterialDialog.Builder(LiveThread.this)
.title(R.string.livethread_loading_title)
.content(R.string.misc_please_wait)
.progress(true, 100)
.cancelable(false)
.show();
}
@Override
protected Void doInBackground(Void... params) {
try {
thread = new LiveThreadManager(Authentication.reddit).get(getIntent().getStringExtra(EXTRA_LIVEURL));
} catch(Exception e){
}
return null;
}
@Override
public void onPostExecute(Void aVoid) {
if(thread == null){
new AlertDialogWrapper.Builder(LiveThread.this)
.setTitle(R.string.livethread_not_found)
.setMessage(R.string.misc_please_try_again_soon)
.setPositiveButton(R.string.btn_ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
}).setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
finish();
}
}).setCancelable(false).show();
} else {
d.dismiss();
setupAppBar(R.id.toolbar, thread.getTitle(), true, false);
(findViewById(R.id.toolbar)).setBackgroundResource(R.color.md_red_300);
(findViewById(R.id.header_sub)).setBackgroundResource(R.color.md_red_300);
themeSystemBars(Palette.getDarkerColor(getResources().getColor(R.color.md_red_300)));
setRecentBar(getString(R.string.livethread_recents_title, thread.getTitle()), getResources().getColor(R.color.md_red_300));
doPaginator();
}
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
ArrayList<LiveUpdate> updates;
LiveThreadPaginator paginator;
public void doPaginator() {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
paginator = new LiveThreadManager(Authentication.reddit).stream(thread);
updates = new ArrayList<>(paginator.accumulateMerged(5));
return null;
}
@Override
public void onPostExecute(Void aVoid) {
doLiveThreadUpdates();
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
public void doLiveThreadUpdates() {
final PaginatorAdapter adapter = new PaginatorAdapter(this);
baseRecycler.setAdapter(adapter);
doLiveSidebar();
if (thread.getWebsocketUrl() != null && !thread.getWebsocketUrl().isEmpty()) {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
final ObjectReader o = new ObjectMapper().reader();
try {
com.neovisionaries.ws.client.WebSocket ws = new WebSocketFactory().createSocket(thread.getWebsocketUrl());
ws.addListener(new WebSocketListener() {
@Override
public void onStateChanged(com.neovisionaries.ws.client.WebSocket websocket, WebSocketState newState) throws Exception {
}
@Override
public void onConnected(com.neovisionaries.ws.client.WebSocket websocket, Map<String, List<String>> headers) throws Exception {
}
@Override
public void onConnectError(com.neovisionaries.ws.client.WebSocket websocket, WebSocketException cause) throws Exception {
}
@Override
public void onDisconnected(com.neovisionaries.ws.client.WebSocket websocket, WebSocketFrame serverCloseFrame, WebSocketFrame clientCloseFrame, boolean closedByServer) throws Exception {
}
@Override
public void onFrame(com.neovisionaries.ws.client.WebSocket websocket, WebSocketFrame frame) throws Exception {
}
@Override
public void onContinuationFrame(com.neovisionaries.ws.client.WebSocket websocket, WebSocketFrame frame) throws Exception {
}
@Override
public void onTextFrame(com.neovisionaries.ws.client.WebSocket websocket, WebSocketFrame frame) throws Exception {
}
@Override
public void onBinaryFrame(com.neovisionaries.ws.client.WebSocket websocket, WebSocketFrame frame) throws Exception {
}
@Override
public void onCloseFrame(com.neovisionaries.ws.client.WebSocket websocket, WebSocketFrame frame) throws Exception {
}
@Override
public void onPingFrame(com.neovisionaries.ws.client.WebSocket websocket, WebSocketFrame frame) throws Exception {
}
@Override
public void onPongFrame(com.neovisionaries.ws.client.WebSocket websocket, WebSocketFrame frame) throws Exception {
}
@Override
public void onTextMessage(com.neovisionaries.ws.client.WebSocket websocket, String s) throws Exception {
LogUtil.v("Recieved" + s);
if (s.contains("\"type\": \"update\"")) {
try {
LiveUpdate u = new LiveUpdate(o.readTree(s).get("payload").get("data"));
updates.add(0, u);
runOnUiThread(new Runnable() {
@Override
public void run() {
adapter.notifyItemInserted(0);
baseRecycler.smoothScrollToPosition(0);
}
});
} catch (IOException e) {
e.printStackTrace();
}
} else if (s.contains("embeds_ready")) {
String node = updates.get(0).getDataNode().toString();
LogUtil.v("Getting");
try {
node = node.replace("\"embeds\":[]", "\"embeds\":" + o.readTree(s).get("payload").get("media_embeds").toString());
LiveUpdate u = new LiveUpdate(o.readTree(node));
updates.set(0, u);
runOnUiThread(new Runnable() {
@Override
public void run() {
adapter.notifyItemChanged(0);
}
});
} catch (Exception e) {
e.printStackTrace();
}
} /* todoelse if(s.contains("delete")){
updates.remove(0);
adapter.notifyItemRemoved(0);
}*/
}
@Override
public void onBinaryMessage(com.neovisionaries.ws.client.WebSocket websocket, byte[] binary) throws Exception {
}
@Override
public void onSendingFrame(com.neovisionaries.ws.client.WebSocket websocket, WebSocketFrame frame) throws Exception {
}
@Override
public void onFrameSent(com.neovisionaries.ws.client.WebSocket websocket, WebSocketFrame frame) throws Exception {
}
@Override
public void onFrameUnsent(com.neovisionaries.ws.client.WebSocket websocket, WebSocketFrame frame) throws Exception {
}
@Override
public void onError(com.neovisionaries.ws.client.WebSocket websocket, WebSocketException cause) throws Exception {
}
@Override
public void onFrameError(com.neovisionaries.ws.client.WebSocket websocket, WebSocketException cause, WebSocketFrame frame) throws Exception {
}
@Override
public void onMessageError(com.neovisionaries.ws.client.WebSocket websocket, WebSocketException cause, List<WebSocketFrame> frames) throws Exception {
}
@Override
public void onMessageDecompressionError(com.neovisionaries.ws.client.WebSocket websocket, WebSocketException cause, byte[] compressed) throws Exception {
}
@Override
public void onTextMessageError(com.neovisionaries.ws.client.WebSocket websocket, WebSocketException cause, byte[] data) throws Exception {
}
@Override
public void onSendError(com.neovisionaries.ws.client.WebSocket websocket, WebSocketException cause, WebSocketFrame frame) throws Exception {
}
@Override
public void onUnexpectedError(com.neovisionaries.ws.client.WebSocket websocket, WebSocketException cause) throws Exception {
}
@Override
public void handleCallbackError(com.neovisionaries.ws.client.WebSocket websocket, Throwable cause) throws Exception {
}
@Override
public void onSendingHandshake(com.neovisionaries.ws.client.WebSocket websocket, String requestLine, List<String[]> headers) throws Exception {
}
});
ws.connect();
} catch (IOException e) {
e.printStackTrace();
} catch (WebSocketException e) {
e.printStackTrace();
}
return null;
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
public class PaginatorAdapter extends RecyclerView.Adapter<PaginatorAdapter.ItemHolder> {
private LayoutInflater layoutInflater;
public PaginatorAdapter(Context context) {
layoutInflater = LayoutInflater.from(context);
}
@Override
public PaginatorAdapter.ItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = layoutInflater.inflate(R.layout.live_list_item, parent, false);
return new ItemHolder(itemView);
}
@Override
public void onBindViewHolder(final PaginatorAdapter.ItemHolder holder, int position) {
final LiveUpdate u = updates.get(position);
holder.title.setText("/u/" + u.getAuthor() + " " + TimeUtils.getTimeAgo(u.getCreated().getTime(), LiveThread.this));
if (u.getBody().isEmpty()) {
holder.info.setVisibility(View.GONE);
} else {
holder.info.setVisibility(View.VISIBLE);
holder.info.setTextHtml(Html.fromHtml(u.getDataNode().get("body_html").asText()), "NO SUBREDDIT");
}
holder.title.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(LiveThread.this, Profile.class);
i.putExtra(Profile.EXTRA_PROFILE, u.getAuthor());
startActivity(i);
}
});
holder.imageArea.setVisibility(View.GONE);
holder.twitterArea.setVisibility(View.GONE);
holder.twitterArea.stopLoading();
if (u.getEmbeds().size() == 0) {
holder.go.setVisibility(View.GONE);
} else {
final String url = u.getEmbeds().get(0).getUrl();
holder.go.setVisibility(View.VISIBLE);
holder.go.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(LiveThread.this, Website.class);
i.putExtra(Website.EXTRA_URL, url);
startActivity(i);
}
});
final String host = URI.create(url).getHost().toLowerCase();
if (ContentType.hostContains(host, "imgur.com")) {
LogUtil.v("Imgur");
holder.imageArea.setVisibility(View.VISIBLE);
holder.imageArea.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
holder.go.callOnClick();
}
});
((Reddit) getApplicationContext()).getImageLoader().displayImage(url, holder.imageArea);
} else if (ContentType.hostContains(host, "twitter.com")) {
LogUtil.v("Twitter");
holder.twitterArea.setVisibility(View.VISIBLE);
new LoadTwitter(holder.twitterArea, url).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
}
public class LoadTwitter extends AsyncTask<String, Void, Void> {
private OkHttpClient client;
private Gson gson;
String url;
private WebView view;
TwitterObject twitter;
public LoadTwitter(@NotNull WebView view, @NotNull String url) {
this.view = view;
this.url = url;
client = Reddit.client;
gson = new Gson();
}
public void parseJson() {
try {
JsonObject result = HttpUtil.getJsonObject(client, gson, "https://publish.twitter.com/oembed?url=" + url, null);
LogUtil.v("Got " + Html.fromHtml(result.toString()));
twitter = new ObjectMapper().readValue(result.toString(), TwitterObject.class);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected Void doInBackground(final String... sub) {
parseJson();
return null;
}
@Override
public void onPostExecute(Void aVoid) {
if (twitter != null && twitter.getHtml() != null) {
view.loadData(twitter.getHtml().replace("//platform.twitter", "https://platform.twitter"), "text/html", "UTF-8");
}
}
}
@Override
public int getItemCount() {
return updates.size();
}
public class ItemHolder extends RecyclerView.ViewHolder {
TextView title;
SpoilerRobotoTextView info;
ImageView imageArea;
WebView twitterArea;
View go;
public ItemHolder(View itemView) {
super(itemView);
title = (TextView) itemView.findViewById(R.id.title);
info = (SpoilerRobotoTextView) itemView.findViewById(R.id.body);
go = itemView.findViewById(R.id.go);
imageArea = (ImageView) itemView.findViewById(R.id.image_area);
twitterArea = (WebView) itemView.findViewById(R.id.twitter_area);
twitterArea.setWebChromeClient(new WebChromeClient());
twitterArea.getSettings().setJavaScriptEnabled(true);
twitterArea.setBackgroundColor(Color.TRANSPARENT);
twitterArea.setLayerType(WebView.LAYER_TYPE_SOFTWARE, null);
}
}
}
public void doLiveSidebar() {
findViewById(R.id.loader).setVisibility(View.GONE);
final View dialoglayout = findViewById(R.id.sidebarsub);
dialoglayout.findViewById(R.id.sub_stuff).setVisibility(View.GONE);
((TextView) dialoglayout.findViewById(R.id.sub_infotitle)).setText((thread.getState() ? "LIVE: " : "") + thread.getTitle());
((TextView) dialoglayout.findViewById(R.id.active_users)).setText(thread.getLocalizedViewerCount() + " viewing");
((TextView) dialoglayout.findViewById(R.id.active_users)).setText(thread.getLocalizedViewerCount());
{
final String text = thread.getDataNode().get("resources_html").asText();
final SpoilerRobotoTextView body = (SpoilerRobotoTextView) findViewById(R.id.sidebar_text);
CommentOverflow overflow = (CommentOverflow) findViewById(R.id.commentOverflow);
setViews(text, "none", body, overflow);
}
{
final String text = thread.getDataNode().get("description_html").asText();
final SpoilerRobotoTextView body = (SpoilerRobotoTextView) findViewById(R.id.sub_title);
CommentOverflow overflow = (CommentOverflow) findViewById(R.id.sub_title_overflow);
setViews(text, "none", body, overflow);
}
}
private void setViews(String rawHTML, String subreddit, SpoilerRobotoTextView firstTextView, CommentOverflow commentOverflow) {
if (rawHTML.isEmpty()) {
return;
}
List<String> blocks = SubmissionParser.getBlocks(rawHTML);
int startIndex = 0;
// the <div class="md"> case is when the body contains a table or code block first
if (!blocks.get(0).equals("<div class=\"md\">")) {
firstTextView.setVisibility(View.VISIBLE);
firstTextView.setTextHtml(blocks.get(0), subreddit);
startIndex = 1;
} else {
firstTextView.setText("");
firstTextView.setVisibility(View.GONE);
}
if (blocks.size() > 1) {
if (startIndex == 0) {
commentOverflow.setViews(blocks, subreddit);
} else {
commentOverflow.setViews(blocks.subList(startIndex, blocks.size()), subreddit);
}
SidebarLayout sidebar = (SidebarLayout) findViewById(R.id.drawer_layout);
for (int i = 0; i < commentOverflow.getChildCount(); i++) {
View maybeScrollable = commentOverflow.getChildAt(i);
if (maybeScrollable instanceof HorizontalScrollView) {
sidebar.addScrollable(maybeScrollable);
}
}
} else {
commentOverflow.removeAllViews();
}
}
}