package treehou.se.habit.ui.inbox;
import android.os.Bundle;
import android.support.design.widget.Snackbar;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.util.Log;
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 com.trello.rxlifecycle.components.support.RxFragment;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder;
import io.realm.Realm;
import se.treehou.ng.ohcommunicator.connector.models.OHInboxItem;
import se.treehou.ng.ohcommunicator.services.Connector;
import se.treehou.ng.ohcommunicator.services.IServerHandler;
import treehou.se.habit.R;
import treehou.se.habit.core.db.model.ServerDB;
import treehou.se.habit.ui.adapter.InboxAdapter;
import treehou.se.habit.util.RxUtil;
public class InboxListFragment extends RxFragment {
private static final String TAG = "InboxListFragment";
private static final String ARG_SERVER = "argServer";
@BindView(R.id.list) RecyclerView listView;
@BindView(R.id.error_view) View empty;
private Realm relam;
private ServerDB server;
private InboxAdapter adapter;
private List<OHInboxItem> items = new ArrayList<>();
private boolean showIgnored = false;
private MenuItem actionHide;
private MenuItem actionShow;
private Unbinder unbinder;
/**
* Creates a new instance of inbox list fragment.
*
* @param serverId the server to connect to.
* @return new fragment instance.
*/
public static InboxListFragment newInstance(long serverId) {
InboxListFragment fragment = new InboxListFragment();
Bundle args = new Bundle();
args.putLong(ARG_SERVER, serverId);
fragment.setArguments(args);
return fragment;
}
/**
* Mandatory empty constructor for the fragment manager to instantiate the
* fragment (e.g. upon screen orientation changes).
*/
public InboxListFragment() {}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
relam = Realm.getDefaultInstance();
server = ServerDB.load(relam, getArguments().getLong(ARG_SERVER));
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_inbox, container, false);
unbinder = ButterKnife.bind(this, view);
setupActionbar();
hookupInboxList();
setHasOptionsMenu(true);
return view;
}
/**
* Setup inbox list.
*/
private void hookupInboxList(){
GridLayoutManager gridLayoutManager = new GridLayoutManager(getActivity(), 1);
listView.setLayoutManager(gridLayoutManager);
listView.setItemAnimator(new DefaultItemAnimator());
ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.RIGHT) {
@Override
public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
if (viewHolder instanceof InboxAdapter.IgnoreInboxHolder) return ItemTouchHelper.LEFT;
return super.getSwipeDirs(recyclerView, viewHolder);
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
if(ItemTouchHelper.RIGHT == swipeDir){
OHInboxItem item = adapter.getItem(viewHolder.getAdapterPosition());
ignoreInboxItem(item);
}
if(ItemTouchHelper.LEFT == swipeDir){
OHInboxItem item = adapter.getItem(viewHolder.getAdapterPosition());
unignoreInboxItem(item);
}
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
};
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemTouchCallback);
itemTouchHelper.attachToRecyclerView(listView);
adapter = new InboxAdapter(getContext(), server);
listView.setAdapter(adapter);
}
/**
* Set up actionbar
*/
private void setupActionbar() {
ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
if(actionBar != null) {
actionBar.setTitle(R.string.inbox);
}
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.inbox, menu);
actionHide = menu.findItem(R.id.action_hide);
actionHide.setOnMenuItemClickListener(item -> {
showIgnoredItems(false);
return true;
});
actionShow = menu.findItem(R.id.action_show);
actionShow.setOnMenuItemClickListener(item -> {
showIgnoredItems(true);
return true;
});
updateIgnoreButtons(showIgnored);
}
/**
* Set if ignored items should be shown.
* @param showIgnored true to show ignored items, else false.
*/
private void showIgnoredItems(boolean showIgnored){
this.showIgnored = showIgnored;
setItems(items, showIgnored);
updateIgnoreButtons(showIgnored);
final View rootView = getView();
if(rootView != null) {
Snackbar.make(rootView, showIgnored ? getString(R.string.show_ignored) : getString(R.string.hide_ignored), Snackbar.LENGTH_SHORT).show();
}
}
/**
* Update icons for showing if viewing ignored items or not.
*
* @param showIgnored True to show ignored ignored items else false.
*/
private void updateIgnoreButtons(boolean showIgnored){
actionShow.setVisible(!showIgnored);
actionHide.setVisible(showIgnored);
}
/**
* Set all the items that should be displayed in list.
* Clears and updates adapter accordingly.
*
* @param items the items to show.
* @param showIgnored true to filter out ignored items.
*/
private void setItems(List<OHInboxItem> items, boolean showIgnored){
List<OHInboxItem> inboxItems = new ArrayList<>(items);
Log.d(TAG, "Received items " + inboxItems);
Collections.sort(inboxItems, new InboxItemComparator());
adapter.clear();
if (!showIgnored) {
for (Iterator<OHInboxItem> it = inboxItems.iterator(); it.hasNext();) {
if (it.next().isIgnored()) {
it.remove();
}
}
}
adapter.addAll(inboxItems);
}
/**
* Ignore inbox item.
* Removes the inbox item from the list.
* Sends ignore request to the server.
*
* @param item the item to hide.
*/
private void ignoreInboxItem(final OHInboxItem item){
item.setFlag(OHInboxItem.FLAG_IGNORED);
IServerHandler serverHandler = new Connector.ServerHandler(server.toGeneric(), getContext());
serverHandler.ignoreInboxItem(item);
final View rootView = getView();
if(rootView != null) {
Snackbar.make(rootView, R.string.hide_item, Snackbar.LENGTH_LONG)
.setAction(R.string.undo, view -> {
unignoreInboxItem(item);
Snackbar.make(rootView, R.string.restore_item, Snackbar.LENGTH_SHORT).show();
}).show();
}
setItems(items, showIgnored);
}
/**
* Unignore inbox item.
* Removes the inbox item from the list.
* Sends unignore request to the server.
*
* @param item the item to hide.
*/
private void unignoreInboxItem(final OHInboxItem item) {
item.setFlag("");
IServerHandler serverHandler = new Connector.ServerHandler(server.toGeneric(), getContext());
serverHandler.unignoreInboxItem(item);
setItems(items, showIgnored);
}
@Override
public void onResume() {
super.onResume();
showErrorView(false);
IServerHandler serverHandler = new Connector.ServerHandler(server.toGeneric(), getContext());
serverHandler.requestInboxItemsRx()
.compose(RxUtil.newToMainSchedulers())
.compose(this.bindToLifecycle())
.subscribe(ohInboxItems -> {
showErrorView(false);
setItems(ohInboxItems, showIgnored);
}, throwable -> {
showErrorView(true);
});
}
/**
* Updates ui to show error.
* @param showError the error to show.
*/
private void showErrorView(boolean showError){
if(showError){
empty.setVisibility(View.VISIBLE);
listView.setVisibility(View.GONE);
}
else {
empty.setVisibility(View.GONE);
listView.setVisibility(View.VISIBLE);
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
@Override
public void onDestroy() {
super.onDestroy();
relam.close();
}
/**
* Comparator for sorting inbox item in list.
*/
private static class InboxItemComparator implements Comparator<OHInboxItem> {
@Override
public int compare(OHInboxItem lhs, OHInboxItem rhs) {
int inboxCompare = lhs.getLabel().compareTo(rhs.getLabel());
if(inboxCompare == 0){
return lhs.getThingUID().compareTo(rhs.getThingUID());
}
return inboxCompare;
}
}
}