package com.piusvelte.sonet.fragment;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.KeyEvent;
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.widget.EditText;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;
import com.piusvelte.sonet.R;
import com.piusvelte.sonet.Sonet;
import com.piusvelte.sonet.loader.CommentsLoader;
import com.piusvelte.sonet.loader.LikeCommentLoader;
import com.piusvelte.sonet.loader.SendCommentLoader;
import com.piusvelte.sonet.provider.Entity;
import com.piusvelte.sonet.provider.Statuses;
import com.piusvelte.sonet.social.Client;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import static com.piusvelte.sonet.Sonet.MYSPACE;
/**
* Created by bemmanuel on 4/21/15.
*/
public class CommentsList extends ListFragment
implements TextWatcher, View.OnKeyListener, View.OnClickListener {
private static final int LOADER_COMMENTS = 0;
private static final int LOADER_SEND = 1;
private static final int LOADER_LIKE = 2;
private static final String DIALOG_OPTIONS = "dialog:options";
private static final int REQUEST_OPTIONS = 0;
private static final String ARG_DATA = "data";
private static final String ARG_ESID = "esid";
private static final String ARG_SID = "sid";
private static final String ARG_DO_LIKE = "do_like";
private static final String ARG_MESSAGE = "message";
private static final String STATE_PENDING_LOADERS = "state:pending_loaders";
private static final String STATE_MESSAGE = "state:message";
private int mService = Sonet.INVALID_SERVICE;
private String mSid = null;
private String mEsid = null;
private List<HashMap<String, String>> mComments = new ArrayList<>();
private String mServiceName = null;
@Nullable
private Client mClient;
private EditText mMessage;
private ImageButton mSend;
private TextView mCount;
private SimpleAdapter mAdapter;
private View mLoadingView;
private CommentsLoaderCallbacks mCommentsLoaderCallbacks = new CommentsLoaderCallbacks(this);
private SendLoaderCallbacks mSendLoaderCallbacks = new SendLoaderCallbacks(this);
private LikeLoaderCallbacks mLikeLoaderCallbacks = new LikeLoaderCallbacks(this);
// TODO stop this
@Deprecated
@NonNull
private Set<Integer> mPendingLoaders = new HashSet<>();
public static CommentsList newInstance(@NonNull Uri data) {
CommentsList commentsList = new CommentsList();
Bundle args = new Bundle();
args.putString(ARG_DATA, data.toString());
commentsList.setArguments(args);
return commentsList;
}
public void setData(@NonNull Uri data) {
getArguments().putString(ARG_DATA, data.toString());
if (isResumed()) {
refresh();
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.comments_list_fragment, container, false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mMessage = (EditText) view.findViewById(R.id.message);
mSend = (ImageButton) view.findViewById(R.id.send);
mCount = (TextView) view.findViewById(R.id.count);
mLoadingView = view.findViewById(R.id.loading);
mMessage.addTextChangedListener(this);
mMessage.setOnKeyListener(this);
mSend.setOnClickListener(this);
mAdapter = new SimpleAdapter(getActivity(),
mComments,
R.layout.comment,
new String[] { Entity.FRIEND,
Statuses.MESSAGE,
Statuses.CREATEDTEXT,
getString(R.string.like) },
new int[] { R.id.friend,
R.id.message,
R.id.created,
R.id.like });
setListAdapter(mAdapter);
if (savedInstanceState != null) {
mMessage.setText(savedInstanceState.getString(STATE_MESSAGE));
}
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setHasOptionsMenu(true);
mLoadingView.setVisibility(View.VISIBLE);
LoaderManager loaderManager = getLoaderManager();
Bundle args = new Bundle();
args.putString(ARG_DATA, getArguments().getString(ARG_DATA));
getLoaderManager().initLoader(LOADER_COMMENTS, args, new CommentsLoaderCallbacks(this));
if (loaderManager.getLoader(LOADER_SEND) != null) {
loaderManager.initLoader(LOADER_SEND, null, mSendLoaderCallbacks);
}
if (loaderManager.getLoader(LOADER_LIKE) != null) {
loaderManager.initLoader(LOADER_LIKE, null, mLikeLoaderCallbacks);
}
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.menu_comments, menu);
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
int loaderIndex = 0;
int[] loaders = new int[mPendingLoaders.size()];
for (Integer loader : mPendingLoaders) {
loaders[loaderIndex] = loader;
loaderIndex++;
}
outState.putIntArray(STATE_PENDING_LOADERS, loaders);
outState.putString(STATE_MESSAGE, mMessage.getText().toString());
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int itemId = item.getItemId();
if (itemId == R.id.menu_comments_refresh) {
refresh();
}
return super.onOptionsItemSelected(item);
}
@Override
public void onDestroyView() {
mMessage = null;
mSend = null;
mCount = null;
mLoadingView = null;
super.onDestroyView();
}
private void setCommentStatus(int position, String status) {
if (mComments.size() > position) {
HashMap<String, String> comment = mComments.get(position);
comment.put(getString(R.string.like), status);
mComments.set(position, comment);
mAdapter.notifyDataSetChanged();
}
}
private void refresh() {
mMessage.setEnabled(false);
mLoadingView.setVisibility(View.VISIBLE);
Bundle args = new Bundle();
args.putString(ARG_DATA, getArguments().getString(ARG_DATA));
getLoaderManager().restartLoader(LOADER_COMMENTS, args, mCommentsLoaderCallbacks);
}
@Override
public void onListItemClick(ListView list, View view, final int position, long id) {
super.onListItemClick(list, view, position, id);
HashMap<String, String> comment = mComments.get(position);
final String sid = comment.get(Statuses.SID);
final String liked = comment.get(getString(R.string.like));
final boolean doLike = !getString(R.string.like).equals(liked);
// wait for previous attempts to finish
if (!TextUtils.isEmpty(liked) && !liked.equals(getString(R.string.loading))) {
// parse comment body, as in StatusDialog.java
Matcher m = Sonet.getLinksMatcher(mComments.get(position).get(Statuses.MESSAGE));
int count = 0;
while (m.find()) {
count++;
}
String[] items = new String[count + 1];
items[0] = mClient.getLikeText(doLike);
count = 1;
m.reset();
while (m.find()) {
items[count++] = m.group();
}
CommentOptionsDialogFragment.newInstance(REQUEST_OPTIONS, items, sid, doLike)
.show(getChildFragmentManager(), DIALOG_OPTIONS);
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// NO-OP
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// NO-OP
}
@Override
public void afterTextChanged(Editable s) {
mCount.setText(Integer.toString(s.toString().length()));
}
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
mCount.setText(Integer.toString(mMessage.getText().toString().length()));
return false;
}
@Override
public void onClick(View v) {
if (v == mSend) {
if (!TextUtils.isEmpty(mMessage.getText().toString()) && mClient != null) {
mMessage.setEnabled(false);
mSend.setEnabled(false);
mLoadingView.setVisibility(View.VISIBLE);
Bundle args = new Bundle();
args.putString(ARG_SID, mSid);
args.putString(ARG_MESSAGE, mMessage.getText().toString());
getLoaderManager().restartLoader(LOADER_SEND, null, mSendLoaderCallbacks);
} else {
(Toast.makeText(getActivity(), "error parsing message body", Toast.LENGTH_LONG)).show();
mMessage.setEnabled(true);
mSend.setEnabled(true);
}
}
}
private void setComments(CommentsLoader.Result result) {
mLoadingView.setVisibility(View.GONE);
mComments.clear();
if (result != null) {
mClient = result.client;
mService = result.service;
mSid = result.sid;
mEsid = result.esid;
mServiceName = result.serviceName;
mMessage.setText("");
if (result.isCommentable) {
if (!TextUtils.isEmpty(result.messagePretext)) {
mMessage.append(result.messagePretext);
}
} else {
mSend.setEnabled(false);
mMessage.setEnabled(false);
mMessage.setText(R.string.uncommentable);
}
if (result.isLikeable) {
setCommentStatus(0, result.likeText);
} else {
setCommentStatus(0, getString(R.string.unlikable));
}
mMessage.setEnabled(true);
if (result.socialClientComments != null && result.socialClientComments.size() > 0) {
mComments.addAll(result.socialClientComments);
}
}
mAdapter.notifyDataSetChanged();
}
private void onSendResult(Boolean result) {
mLoadingView.setVisibility(View.GONE);
if (Boolean.TRUE.equals(result)) {
Toast.makeText(getActivity(), mServiceName + " " + getString(R.string.success), Toast.LENGTH_LONG).show();
} else if (mService == MYSPACE) {
// myspace permissions
Toast.makeText(getActivity(), getActivity().getResources().getStringArray(R.array.service_entries)[MYSPACE] + getString(
R.string.failure) + " " + getString(R.string.myspace_permissions_message), Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getActivity(), mServiceName + " " + getString(R.string.failure), Toast.LENGTH_LONG).show();
}
}
private void onLikeResult(LikeCommentLoader.Result result) {
mLoadingView.setVisibility(View.GONE);
if (result != null) {
Toast.makeText(getActivity(), mServiceName + " " + getString(result.wasSuccessful ? R.string.success : R.string.failure),
Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getActivity(), mServiceName + " " + getString(R.string.failure), Toast.LENGTH_LONG).show();
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_OPTIONS:
if (resultCode == Activity.RESULT_OK) {
int which = ItemsDialogFragment.getWhich(data, 0);
if (which == 0) {
// like/unlike
String sid = CommentOptionsDialogFragment.getSid(data);
boolean doLike = CommentOptionsDialogFragment.getDoLiked(data, false);
mLoadingView.setVisibility(View.VISIBLE);
Bundle args = new Bundle();
args.putString(ARG_ESID, mEsid);
args.putString(ARG_SID, sid);
args.putBoolean(ARG_DO_LIKE, doLike);
getLoaderManager().restartLoader(LOADER_LIKE, args, mLikeLoaderCallbacks);
} else {
String[] items = ItemsDialogFragment.getItems(data);
if (items != null && which < items.length && items[which] != null) {
// open link
startActivity(new Intent(Intent.ACTION_VIEW).setData(Uri.parse(items[which])));
} else {
(Toast.makeText(getActivity(), getString(R.string.error_status), Toast.LENGTH_LONG)).show();
}
}
}
break;
default:
super.onActivityResult(requestCode, resultCode, data);
break;
}
}
@Nullable
private Client getClient() {
return mClient;
}
private static class CommentsLoaderCallbacks implements LoaderManager.LoaderCallbacks<CommentsLoader.Result> {
private CommentsList mCommentsList;
public CommentsLoaderCallbacks(CommentsList commentsList) {
mCommentsList = commentsList;
}
@Override
public Loader<CommentsLoader.Result> onCreateLoader(int id, Bundle args) {
switch (id) {
case LOADER_COMMENTS:
return new CommentsLoader(mCommentsList.getActivity(),
Uri.parse(mCommentsList.getArguments().getString(ARG_DATA)));
default:
return null;
}
}
@Override
public void onLoadFinished(Loader<CommentsLoader.Result> loader, CommentsLoader.Result data) {
switch (loader.getId()) {
case LOADER_COMMENTS:
mCommentsList.setComments(data);
break;
}
}
@Override
public void onLoaderReset(Loader<CommentsLoader.Result> loader) {
// NO-OP
}
}
private static class SendLoaderCallbacks implements LoaderManager.LoaderCallbacks<Boolean> {
private CommentsList mCommentsList;
public SendLoaderCallbacks(CommentsList commentsList) {
mCommentsList = commentsList;
}
@Override
public Loader<Boolean> onCreateLoader(int id, Bundle args) {
switch (id) {
case LOADER_SEND:
return new SendCommentLoader(mCommentsList.getActivity(),
mCommentsList.getClient(),
args.getString(ARG_SID),
args.getString(ARG_MESSAGE));
default:
return null;
}
}
@Override
public void onLoadFinished(Loader<Boolean> loader, Boolean data) {
switch (loader.getId()) {
case LOADER_SEND:
mCommentsList.onSendResult(data);
loader.abandon();
break;
}
}
@Override
public void onLoaderReset(Loader<Boolean> loader) {
// NO-OP
}
}
private static class LikeLoaderCallbacks implements LoaderManager.LoaderCallbacks<LikeCommentLoader.Result> {
private CommentsList mCommentsList;
public LikeLoaderCallbacks(CommentsList commentsList) {
mCommentsList = commentsList;
}
@Override
public Loader<LikeCommentLoader.Result> onCreateLoader(int id, Bundle args) {
switch (id) {
case LOADER_LIKE:
return new LikeCommentLoader(mCommentsList.getActivity(),
mCommentsList.getClient(),
args.getString(ARG_SID),
args.getString(ARG_ESID),
args.getBoolean(ARG_DO_LIKE));
default:
return null;
}
}
@Override
public void onLoadFinished(Loader<LikeCommentLoader.Result> loader, LikeCommentLoader.Result data) {
switch (loader.getId()) {
case LOADER_LIKE:
mCommentsList.onLikeResult(data);
break;
}
}
@Override
public void onLoaderReset(Loader<LikeCommentLoader.Result> loader) {
// NO-OP
}
}
}