package edu.gatech.oad.rocket.findmythings;
import android.app.*;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v13.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.text.TextUtils;
import android.view.*;
import android.widget.SearchView;
import edu.gatech.oad.rocket.findmythings.model.MessageBean;
import edu.gatech.oad.rocket.findmythings.control.LoginManager;
import edu.gatech.oad.rocket.findmythings.list.ItemFilterConstraint;
import edu.gatech.oad.rocket.findmythings.service.EndpointUtils;
import edu.gatech.oad.rocket.findmythings.model.Type;
import edu.gatech.oad.rocket.findmythings.util.EnumHelper;
import edu.gatech.oad.rocket.findmythings.util.ErrorDialog;
import edu.gatech.oad.rocket.findmythings.util.ToastHelper;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicReference;
/**
* CS 2340 - FindMyStuff Android App
*
* An activity representing a list of Items. This activity has different
* presentations for handset and tablet-size devices. On handsets, the activity
* presents a list of items, which when touched, lead to a
* {@link ItemDetailActivity} representing item details. On tablets, the
* activity presents the list of items and item details side-by-side using two
* vertical panes.
*
* @author TeamRocket
*/
public class MainActivity extends Activity {
public static final String EXTRA_LIST = "displayedList";
/**
* Quick at-a-glance identifier of the XML layout used for this activity.
*/
private static final int mTabsLayoutRes = R.layout.activity_main_tabs;
/**
* Quick at-a-glance identifier of the strings used to populate this activity's tabs.
*/
private static final int mTabsListRes = R.array.main_tabs;
private static final int mTabsSummaryRes = R.array.main_tabs_summary;
/**
* Cached list of tab strings.
*/
private String[] mTabs = null;
private String[] mTabSummaries = null;
/**
* Used for the AlertDialog when user tries to sign out
*/
private boolean logOut = false;
/**
* Used for querying what Type is being displayed
*/
private ViewPager pager;
/**
* Indirect reference to the search bar in the ActionBar
*/
private MenuItem searchMenuItem;
/**
* Box shown to prevent user interaction during logout
*/
private ProgressDialog mProgressDialog;
private class TypeTabsAdapter extends FragmentPagerAdapter
implements ActionBar.TabListener, ViewPager.OnPageChangeListener {
private final ActionBar mActionBar;
private final ViewPager mViewPager;
TypeTabsAdapter(FragmentManager fragmentManager, ActionBar actionBar, ViewPager pager) {
super(fragmentManager);
mActionBar = actionBar;
mViewPager = pager;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
mViewPager.setOffscreenPageLimit(mTabs.length);
for (int i = 0; i < mTabs.length; i++) {
String mTab = mTabs[i];
String mTabDesc = mTabSummaries[i];
ActionBar.Tab tab = mActionBar.newTab();
tab.setTabListener(this);
tab.setText(mTab);
tab.setContentDescription(mTabDesc);
mActionBar.addTab(tab);
}
notifyDataSetChanged();
}
@Override
public Fragment getItem(int position) {
Type thisType = getDisplayedTypeInPager(position);
return ItemListFragment.newInstance(thisType);
}
@Override
public void onPageSelected(int i) {
mActionBar.setSelectedNavigationItem(i);
}
@Override
public int getCount() {
return mTabs.length;
}
@Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
mViewPager.setCurrentItem(tab.getPosition());
}
@Override public void onPageScrolled(int i, float v, int i2) {}
@Override public void onPageScrollStateChanged(int i) {}
@Override public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {}
@Override public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {}
}
/**
* creates window with correct layout
* @param savedInstanceState Initializing bundle
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(mTabsLayoutRes);
mTabs = getResources().getStringArray(mTabsListRes);
mTabSummaries = getResources().getStringArray(mTabsSummaryRes);
pager = (ViewPager)findViewById(R.id.pager);
new TypeTabsAdapter(getFragmentManager(), getActionBar(), pager);
ActionBar actionBar = getActionBar();
actionBar.setDisplayHomeAsUpEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
actionBar.setDisplayShowTitleEnabled(true);
}
private Type getDisplayedTypeInPager(int pagerPosition) {
int offIndex = pagerPosition % mTabs.length;
return offIndex == 0 ? null : EnumHelper.forInt(offIndex-1, Type.class);
}
protected Type getDisplayedType() {
return getDisplayedTypeInPager(pager.getCurrentItem());
}
protected void setDisplayedType(Type newType) {
int idx = 0;
if (newType != null) idx = newType.ordinal() + 1;
ActionBar actionBar = getActionBar();
actionBar.selectTab(actionBar.getTabAt(idx));
pager.setCurrentItem(idx, false);
}
private ItemListFragment getDisplayedFragment(int position) {
String tag = "android:switcher:" + pager.getId() + ":" + position;
return (ItemListFragment)getFragmentManager().findFragmentByTag(tag);
}
private ItemListFragment getDisplayedFragment() {
return getDisplayedFragment(pager.getCurrentItem());
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// Check which request we're responding to
if (requestCode == LoginActivity.LOGIN_REQUEST) {
if (resultCode == RESULT_OK) {
// isLoggedIn stuff happens in onPrepareOptionsMenu
ToastHelper.showShort(this, R.string.main_logged_in);
}
} else if (requestCode == SubmitActivity.SUBMIT_REQUEST) {
if (resultCode == RESULT_OK) {
Type switchTo = null; // ALL
if (data.hasExtra(MainActivity.EXTRA_LIST)) {
switchTo = Type.valueOf(data.getStringExtra(MainActivity.EXTRA_LIST));
}
setDisplayedType(switchTo);
ItemListFragment frag = getDisplayedFragment();
frag.refresh();
}
} else if (requestCode == FilterActivity.FILTER_REQUEST) {
ItemListFragment frag = getDisplayedFragment();
ItemFilterConstraint constraint = null;
if (data != null ) {
constraint = FilterActivity.constraint;
}
// null filter removes filtering
frag.performFilter(constraint);
if (constraint != null && !constraint.isEmpty()) {
startActionMode(new ActionMode.Callback() {
@Override
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
String titleFormat = getString(R.string.filtering_title);
String title = String.format(titleFormat, mTabs[pager.getCurrentItem()]);
actionMode.setTitle(title);
MenuInflater inf = actionMode.getMenuInflater();
inf.inflate(R.menu.activity_main_filtered, menu);
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
return false; // nothing to do, nothing to see
}
@Override
public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
switch (menuItem.getItemId()) {
case R.id.filtering_done:
actionMode.finish();
return true;
default:
return false;
}
}
@Override
public void onDestroyActionMode(ActionMode actionMode) {
getDisplayedFragment().performFilter(null);
}
});
}
}
}
/**
* updates the options menu (login, account, admin button)
* @param menu System action bar menu
*/
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
LoginManager mgr = LoginManager.getLoginManager();
boolean loggedIn = mgr.isLoggedIn();
//Set Login Title
MenuItem loginMenu = menu.findItem(R.id.menu_login);
loginMenu.setTitle(loggedIn ? R.string.main_menu_log_out : R.string.main_menu_log_in);
//Set Account Title
MenuItem accountMenu = menu.findItem(R.id.menu_account);
if (loggedIn) {
accountMenu.setTitle(LoginManager.getLoginManager().getCurrentEmail());
accountMenu.setVisible(true);
} else {
accountMenu.setTitle(R.string.main_title_account);
accountMenu.setVisible(false);
}
//Show/Hide admin button
MenuItem adminMenu = menu.findItem(R.id.menu_admin);
if ((mgr.getCurrentUser()!= null && mgr.getCurrentUser().getAdmin()!=null && !mgr.getCurrentUser().getAdmin() )|| !loggedIn) {
adminMenu.setVisible(false);
} else {
adminMenu.setVisible(true);
}
return true;
}
/**
* creates the options menu and adds the search listener
* @param menu System action bar menu
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main_menu, menu);
searchMenuItem = menu.findItem(R.id.main_search_bar);
SearchView mSearch = (SearchView) searchMenuItem.getActionView();
mSearch.bringToFront();
SearchView.OnQueryTextListener queryTextListener = new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextChange(String newText) {
return true;
}
@Override
public boolean onQueryTextSubmit(String query) {
if (TextUtils.isEmpty(query)) return false;
Intent to = new Intent(MainActivity.this, SearchResultsActivity.class);
to.putExtra(ItemListFragment.ARG_QUERY, query);
Type type = getDisplayedType();
if (type != null) to.putExtra(ItemListFragment.ARG_TYPE, type);
startActivity(to);
overridePendingTransition(R.anim.slide_up_modal, R.anim.hold);
return true;
}
};
mSearch.setOnQueryTextListener(queryTextListener);
return true;
}
/**
* takes care of action when a key is pressed down
* @param keyCode The value in event.getKeyCode().
* @param event description of the event
* @return boolean
*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
//Tells Activity what to do when back key is pressed
if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
return false;
}
if (keyCode == KeyEvent.KEYCODE_SEARCH) {
//Shows the search bar
searchMenuItem.expandActionView();
return true;
}
return super.onKeyDown(keyCode, event);
}
/**
* shows the options that are available for user depending on the item selected (submit/search/login/etc)
* @param item - menu selected
* @return boolean
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.item_list_submit:
return toSubmit();
case R.id.menu_list_filter:
return toActivity(FilterActivity.class, FilterActivity.FILTER_REQUEST);
case R.id.menu_login:
return LoginManager.getLoginManager().isLoggedIn() ? logOut() : toActivity(LoginActivity.class, LoginActivity.LOGIN_REQUEST);
case R.id.menu_account:
return toActivity(AccountActivity.class, AccountActivity.REQUEST_ACCOUNT);
case R.id.menu_admin:
return toActivity(AdminActivity.class, AdminActivity.REQUEST_ADMIN);
default:
return super.onOptionsItemSelected(item);
}
}
/**
* Opens a new SubmitActivity activity with the current type of item.
*/
public boolean toSubmit() {
if (LoginManager.getLoginManager().isLoggedIn()) {
Intent goToNextActivity = new Intent(this, SubmitActivity.class);
Type type = getDisplayedType();
if (type != null) goToNextActivity.putExtra(SubmitActivity.EXTRA_TYPE, type);
startActivityForResult(goToNextActivity, SubmitActivity.SUBMIT_REQUEST);
overridePendingTransition(R.anim.slide_up_modal, R.anim.hold);
}
else {
ErrorDialog toLogin = new ErrorDialog(R.string.main_submit_log_in_message, R.string.main_submit_log_in, R.string.main_submit_log_in_cancel);
AlertDialog.Builder temp = toLogin.getDialog(this,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
MainActivity.this.toActivity(LoginActivity.class, LoginActivity.LOGIN_REQUEST);
}
},
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
//cancel
}
});
temp.show();
}
return true;
}
/**
* Go to a simple modal, wait-for-response activity.
* @param clazz An activity
* @param request An integer expressing the callback evaluated in onActivityResult()
* @return boolean ALWAYS true, when the activity begins
*/
protected <T extends Activity> boolean toActivity(Class<T> clazz, int request) {
Intent to = new Intent(this, clazz);
startActivityForResult(to, request);
overridePendingTransition(R.anim.slide_up_modal, R.anim.hold);
return true;
}
/**
* Logout
* @return boolean: true if logout, false if not
*/
public boolean logOut() {
ErrorDialog toLogin = new ErrorDialog(R.string.main_sign_out_confirm, R.string.main_sign_out_ok, R.string.main_sign_out_cancel);
AtomicReference<AlertDialog.Builder> temp = new AtomicReference<AlertDialog.Builder>(toLogin.getDialog(this,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
logOut = true;
mProgressDialog = ProgressDialog.show(MainActivity.this,
getString(R.string.main_sign_out_title),
getString(R.string.main_sign_out_message), true, false);
new LogoutTask().execute();
}
},
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
logOut = false;
}
}
));
temp.get().show();
return logOut;
}
/**
* Helper class: asynchronously log out and clear the LoginManager NO MATTER WHAT
*/
public class LogoutTask extends AsyncTask<Void, Void, MessageBean> {
@Override
protected MessageBean doInBackground(Void... arg0) {
try {
return EndpointUtils.getEndpoint().account().logout().execute();
} catch (IOException e) {
return null;
}
}
@Override
protected void onPostExecute(final MessageBean output) {
mProgressDialog.dismiss();
mProgressDialog = null;
//Clear current user
LoginManager.getLoginManager().logout();
//Making sense is for squares
Intent newMain = getIntent();
newMain.setFlags(Intent.FLAG_ACTIVITY_TASK_ON_HOME);
newMain.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
finish();
startActivity(newMain);
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
}
}
}