package com.orgzly.android.ui.fragments;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.TypedArray;
import android.database.Cursor;
import android.graphics.Typeface;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.StyleableRes;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import com.orgzly.BuildConfig;
import com.orgzly.R;
import com.orgzly.android.Book;
import com.orgzly.android.SearchQuery;
import com.orgzly.android.provider.ProviderContract;
import com.orgzly.android.provider.clients.BooksClient;
import com.orgzly.android.provider.clients.FiltersClient;
import com.orgzly.android.ui.Loaders;
import com.orgzly.android.util.LogUtils;
import java.util.ArrayList;
import java.util.List;
public class DrawerFragment extends ListFragment
implements
LoaderManager.LoaderCallbacks<Cursor>,
SharedPreferences.OnSharedPreferenceChangeListener {
private static final String TAG = DrawerFragment.class.getName();
/** Name used for {@link android.app.FragmentManager}. */
public static final String FRAGMENT_TAG = DrawerFragment.class.getName();
/* Drawer list items. */
private FiltersItem filtersHeader;
private final List<FilterItem> filters = new ArrayList<>();
private BooksItem booksHeader;
private final List<BookItem> books = new ArrayList<>();
private SettingsItem settingsHeader;
private DrawerFragmentListener mListener;
private ArrayAdapter<DrawerItem> mListAdapter;
private String activeFragmentTag = null;
private DrawerItem selectedItem = null;
/**
* Mandatory empty constructor for the fragment manager to instantiate the
* fragment (e.g. upon screen orientation changes).
*/
public DrawerFragment() {
if (BuildConfig.LOG_DEBUG) LogUtils.d(TAG);
}
public static DrawerFragment getInstance() {
return new DrawerFragment();
}
public void setActiveFragment(String fragmentTag) {
activeFragmentTag = fragmentTag;
updateSelectedItemFromActiveFragment();
}
private void updateSelectedItemFromActiveFragment() {
selectedItem = null;
FragmentActivity activity = getActivity();
if (activity != null) {
Fragment fragment = activity.getSupportFragmentManager().findFragmentByTag(activeFragmentTag);
if (fragment != null) {
/* Find by query string. */
if (QueryFragment.FRAGMENT_TAG.equals(activeFragmentTag)) {
SearchQuery query = ((QueryFragment) fragment).getQuery();
if (query != null) {
for (FilterItem item : filters) {
if (query.toString().equals(item.query)) {
selectedItem = item;
}
}
}
} else if (BooksFragment.FRAGMENT_TAG.equals(activeFragmentTag)) {
selectedItem = booksHeader;
} else if (FiltersFragment.FRAGMENT_TAG.equals(activeFragmentTag)) {
selectedItem = filtersHeader;
} else if (SettingsFragment.FRAGMENT_TAG.equals(activeFragmentTag)) {
selectedItem = settingsHeader;
/* Find by book ID. */
} else if (BookFragment.FRAGMENT_TAG.equals(activeFragmentTag)) {
Book book = ((BookFragment) fragment).getBook();
if (book != null) {
for (BookItem item : books) {
if (book.getId() == item.id) {
selectedItem = item;
}
}
}
}
mListAdapter.notifyDataSetChanged();
}
}
}
@Override
public void onAttach(Context context) {
if (BuildConfig.LOG_DEBUG) LogUtils.d(TAG, getActivity());
super.onAttach(context);
/* This makes sure that the container activity has implemented
* the callback interface. If not, it throws an exception
*/
try {
mListener = (DrawerFragmentListener) getActivity();
} catch (ClassCastException e) {
throw new ClassCastException(getActivity().toString() + " must implement " + DrawerFragmentListener.class);
}
/* Setup drawer list's header items. */
filtersHeader = new FiltersItem();
booksHeader = new BooksItem();
settingsHeader = new SettingsItem();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (BuildConfig.LOG_DEBUG) LogUtils.d(TAG, inflater, container, savedInstanceState);
/* Inflate layout. */
return inflater.inflate(R.layout.fragment_left_drawer, container, false);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
if (BuildConfig.LOG_DEBUG) LogUtils.d(TAG, savedInstanceState);
super.onActivityCreated(savedInstanceState);
mListAdapter = createAdapter();
setListAdapter(mListAdapter);
if (savedInstanceState != null) { // Configuration change.
getActivity().getSupportLoaderManager().initLoader(Loaders.DRAWER_BOOKS, null, this);
getActivity().getSupportLoaderManager().initLoader(Loaders.DRAWER_FILTERS, null, this);
} else {
getActivity().getSupportLoaderManager().restartLoader(Loaders.DRAWER_BOOKS, null, this);
getActivity().getSupportLoaderManager().restartLoader(Loaders.DRAWER_FILTERS, null, this);
}
}
@Override
public void onDestroyView() {
if (BuildConfig.LOG_DEBUG) LogUtils.d(TAG);
super.onDestroyView();
setListAdapter(null);
mListAdapter = null;
}
@Override
public void onDetach() {
if (BuildConfig.LOG_DEBUG) LogUtils.d(TAG);
super.onDetach();
mListener = null;
}
@Override
public void onResume() {
super.onResume();
/* In case books sort order preference has been changed. */
getActivity().getSupportLoaderManager().restartLoader(Loaders.DRAWER_BOOKS, null, this);
/* Start to listen for any preference changes. */
PreferenceManager.getDefaultSharedPreferences(getActivity()).registerOnSharedPreferenceChangeListener(this);
}
@Override
public void onPause() {
super.onPause();
/* Stop listening for preference changed. */
PreferenceManager.getDefaultSharedPreferences(getActivity()).unregisterOnSharedPreferenceChangeListener(this);
}
private ArrayAdapter<DrawerItem> createAdapter() {
return new ArrayAdapter<DrawerItem>(getActivity(), R.layout.item_drawer, R.id.item_drawer_text) {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
ViewHolder holder = (ViewHolder) view.getTag();
if (holder == null) {
holder = new ViewHolder();
holder.container = (ViewGroup) view.findViewById(R.id.item_drawer_container);
holder.text = (TextView) view.findViewById(R.id.item_drawer_text);
holder.leftIcon = (ImageView) view.findViewById(R.id.item_drawer_left_icon);
holder.rightIcon = (ImageView) view.findViewById(R.id.item_drawer_right_icon);
holder.activeFlag = view.findViewById(R.id.item_drawer_active_flag);
view.setTag(holder);
}
DrawerItem item = getItem(position);
// item.textSize, item.leftIconResource});
TypedArray iconAttrs = getContext().obtainStyledAttributes(R.styleable.Icons);
TypedArray fontSizeAttrs = getContext().obtainStyledAttributes(R.styleable.FontSize);
/* Set text size. */
int t = fontSizeAttrs.getDimensionPixelSize(item.textSize, -1);
if (t != -1) {
holder.text.setTextSize(TypedValue.COMPLEX_UNIT_PX, t);
}
/* Set or hide left icon. */
if (item.icon != 0) {
holder.leftIcon.setImageResource(iconAttrs.getResourceId(item.icon, -1));
holder.leftIcon.setVisibility(View.VISIBLE);
} else {
holder.leftIcon.setVisibility(View.INVISIBLE);
}
iconAttrs.recycle();
fontSizeAttrs.recycle();
/* Set or remove right icon. */
if (item.isModified) {
holder.rightIcon.setVisibility(View.VISIBLE);
} else {
holder.rightIcon.setVisibility(View.INVISIBLE);
}
/* Set text typeface. */
holder.text.setTypeface(null, item.typeface);
/* Set alpha. */
view.setAlpha(item.alpha);
/* Mark currently displayed fragment. */
if (item == selectedItem) {
holder.activeFlag.setVisibility(View.VISIBLE);
} else {
holder.activeFlag.setVisibility(View.INVISIBLE);
}
return view;
}
};
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle bundle) {
if (BuildConfig.LOG_DEBUG) LogUtils.d(TAG, id, bundle);
switch (id) {
case Loaders.DRAWER_FILTERS:
return FiltersClient.getCursorLoader(getActivity());
case Loaders.DRAWER_BOOKS:
return BooksClient.getCursorLoader(getActivity());
default:
throw new IllegalArgumentException("Loader id " + id + " unexpected");
}
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
if (BuildConfig.LOG_DEBUG) LogUtils.d(TAG, loader, cursor);
if (mListAdapter == null) {
if (BuildConfig.LOG_DEBUG) LogUtils.d(TAG, "adapter is null, view is destroyed?");
return;
}
switch (loader.getId()) {
case Loaders.DRAWER_FILTERS:
updateFromFiltersCursor(cursor);
updateAdapter();
break;
case Loaders.DRAWER_BOOKS:
updateFromBooksCursor(cursor);
updateAdapter();
break;
}
}
private void updateAdapter() {
updateSelectedItemFromActiveFragment();
mListAdapter.clear();
mListAdapter.add(filtersHeader);
for (DrawerItem item: filters) {
mListAdapter.add(item);
}
mListAdapter.add(booksHeader);
for (DrawerItem item: books) {
mListAdapter.add(item);
}
mListAdapter.add(settingsHeader);
}
private void updateFromFiltersCursor(Cursor cursor) {
filters.clear();
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndex(ProviderContract.Filters.Param.NAME));
String query = cursor.getString(cursor.getColumnIndex(ProviderContract.Filters.Param.QUERY));
FilterItem item = new FilterItem(name, new SearchQuery(query).toString());
filters.add(item);
}
}
private void updateFromBooksCursor(Cursor cursor) {
books.clear();
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndex(ProviderContract.Books.Param.NAME));
long id = cursor.getLong(cursor.getColumnIndex(ProviderContract.Books.Param._ID));
Book book = BooksClient.fromCursor(cursor);
/* Set book name from title if it exists. */
if (book.getOrgFileSettings().getTitle() != null) {
name = book.getOrgFileSettings().getTitle();
}
BookItem item = new BookItem(name, id);
item.isModified = book.isModifiedAfterLastSync();
/* Change opacity for dummy notebook. */
if (book.isDummy()) {
item.alpha = 0.4f;
}
books.add(item);
}
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
if (mListAdapter == null) {
if (BuildConfig.LOG_DEBUG) LogUtils.d(TAG, "adapter is null, view is destroyed?");
}
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
if (mListener != null) {
DrawerItem item = (DrawerItem) l.getItemAtPosition(position);
mListener.onDrawerItemClicked(item);
}
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
/* Restart loader if notebooks sort order changed. */
FragmentActivity activity = getActivity();
if (activity != null && getString(R.string.pref_key_notebooks_sort_order).equals(key)) {
activity.getSupportLoaderManager().restartLoader(Loaders.DRAWER_BOOKS, null, this);
}
}
public interface DrawerFragmentListener {
void onDrawerItemClicked(DrawerItem item);
}
private class ViewHolder {
ViewGroup container;
TextView text;
ImageView leftIcon;
ImageView rightIcon;
View activeFlag;
}
public class DrawerItem {
String name;
float alpha = 1;
boolean isModified = false;
@StyleableRes int icon = 0; // No icon by default
int typeface = Typeface.NORMAL;
@StyleableRes int textSize = R.styleable.FontSize_item_drawer_text_size;
public String toString() {
return name;
}
}
public class FiltersItem extends DrawerItem {
FiltersItem() {
this.name = getString(R.string.searches);
this.icon = R.styleable.Icons_oic_drawer_filters;
this.textSize = R.styleable.FontSize_item_drawer_title_text_size;
}
}
public class FilterItem extends DrawerItem {
public String query;
FilterItem(String name, String query) {
this.name = name;
this.query = query;
}
}
public class BooksItem extends DrawerItem {
BooksItem() {
this.name = getString(R.string.notebooks);
this.icon = R.styleable.Icons_oic_drawer_notebooks;
this.textSize = R.styleable.FontSize_item_drawer_title_text_size;
}
}
public class BookItem extends DrawerItem {
public long id;
BookItem(String name, long id) {
this.name = name;
this.id = id;
}
}
public class SettingsItem extends DrawerItem {
SettingsItem() {
this.name = getString(R.string.settings);
this.icon = R.styleable.Icons_oic_drawer_settings;
this.textSize = R.styleable.FontSize_item_drawer_title_text_size;
}
}
}