package com.orgzly.android.ui.fragments;
import android.content.Context;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.widget.SimpleCursorAdapter;
import android.view.ContextMenu;
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.AdapterView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.ViewFlipper;
import com.orgzly.BuildConfig;
import com.orgzly.R;
import com.orgzly.android.provider.ProviderContract;
import com.orgzly.android.ui.CommonActivity;
import com.orgzly.android.ui.Loaders;
import com.orgzly.android.ui.util.ActivityUtils;
import com.orgzly.android.util.AppPermissions;
import com.orgzly.android.util.LogUtils;
import com.orgzly.android.util.UriUtils;
/**
* Displays user-configurable repositories.
*/
public class ReposFragment extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor> {
private static final String TAG = ReposFragment.class.getName();
/** Name used for {@link android.app.FragmentManager}. */
public static final String FRAGMENT_TAG = ReposFragment.class.getName();
private SimpleCursorAdapter mListAdapter;
private ReposFragmentListener mListener;
private ViewFlipper mViewFlipper;
public static ReposFragment getInstance() {
return new ReposFragment();
}
/**
* Mandatory empty constructor for the fragment manager to instantiate the
* fragment (e.g. upon screen orientation changes).
*/
public ReposFragment() {
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/* Would like to add items to the Options Menu.
* Required (for fragments only) to receive onCreateOptionsMenu() call.
*/
setHasOptionsMenu(true);
setupAdapter();
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
/* This makes sure that the container activity has implemented
* the callback interface. If not, it throws an exception
*/
try {
mListener = (ReposFragmentListener) getActivity();
} catch (ClassCastException e) {
throw new ClassCastException(getActivity().toString() + " must implement " + ReposFragmentListener.class);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_repos, container, false);
mViewFlipper = (ViewFlipper) view.findViewById(R.id.fragment_repos_flipper);
/* Hide or setup new Dropbox repo button. */
View newDropboxRepoButton = view.findViewById(R.id.fragment_repos_dropbox);
if (BuildConfig.IS_DROPBOX_ENABLED) {
newDropboxRepoButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mListener.onRepoNewRequest(R.id.repos_options_menu_item_new_dropbox);
}
});
} else {
newDropboxRepoButton.setVisibility(View.GONE);
}
view.findViewById(R.id.fragment_repos_directory).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mListener.onRepoNewRequest(R.id.repos_options_menu_item_new_external_storage_directory);
}
});
return view;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
/* Request callbacks for Context menu. */
registerForContextMenu(getListView());
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
if (mListener != null) {
mListener.onRepoEditRequest(id);
}
}
private void setupAdapter() {
/* Column field names to be bound. */
String[] columns = new String[] {
ProviderContract.Repos.Param.REPO_URL
};
/* Views which the data will be bound to. */
int[] to = new int[] {
R.id.item_repo_url
};
/* Create adapter using Cursor. */
mListAdapter = new SimpleCursorAdapter(
getActivity(),
R.layout.item_repo,
null,
columns,
to,
0);
mListAdapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
@Override
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
TextView textView;
switch (view.getId()) {
case R.id.item_repo_url:
if (! cursor.isNull(columnIndex)) {
textView = (TextView) view;
textView.setText(UriUtils.friendlyUri(cursor.getString(columnIndex)));
}
return true;
}
return false;
}
});
setListAdapter(mListAdapter);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
if (BuildConfig.LOG_DEBUG) LogUtils.d(TAG, savedInstanceState);
super.onActivityCreated(savedInstanceState);
/* Delay to avoid brief displaying of no-repos view. */
new android.os.Handler().postDelayed(new Runnable() {
@Override
public void run() {
FragmentActivity activity = getActivity();
if (activity != null) {
activity.getSupportLoaderManager()
.initLoader(Loaders.REPOS_FRAGMENT, null, ReposFragment.this);
}
}
}, 100);
}
@Override
public void onResume() {
if (BuildConfig.LOG_DEBUG) LogUtils.d(TAG);
super.onResume();
/* Close soft keyboard. Required when coming back from one of the RepoFragment fragments. */
ActivityUtils.closeSoftKeyboard(getActivity());
}
/**
* Callback for options menu.
*/
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
if (BuildConfig.LOG_DEBUG) LogUtils.d(TAG, menu, inflater);
inflater.inflate(R.menu.repos_actions, menu);
if (! BuildConfig.IS_DROPBOX_ENABLED) {
menu.findItem(R.id.repos_options_menu_item_new).getSubMenu()
.removeItem(R.id.repos_options_menu_item_new_dropbox);
}
}
/**
* Callback for options menu.
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.repos_options_menu_item_new_dropbox:
mListener.onRepoNewRequest(item.getItemId());
return true;
case R.id.repos_options_menu_item_new_external_storage_directory:
if (AppPermissions.isGrantedOrRequest((CommonActivity) getActivity(), AppPermissions.FOR_LOCAL_REPO)) {
mListener.onRepoNewRequest(item.getItemId());
}
return true;
default:
return super.onOptionsItemSelected(item);
}
}
/*
* Context menu.
*/
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
getActivity().getMenuInflater().inflate(R.menu.repos_context, menu);
}
@Override
public boolean onContextItemSelected(MenuItem item) {
/* Get ID of the item. */
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
switch (item.getItemId()) {
case R.id.repos_context_menu_delete:
mListener.onRepoDeleteRequest(info.id);
return true;
default:
return super.onContextItemSelected(item);
}
}
@Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
return new CursorLoader(
getActivity(),
ProviderContract.Repos.ContentUri.repos(),
null,
null,
null,
ProviderContract.Repos.Param.REPO_URL);
}
@Override
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
/**
* Swapping instead of changing Cursor here, to keep the old one open.
* Loader should release the old Cursor - see note in
* {@link LoaderManager.LoaderCallbacks#onLoadFinished).
*/
mListAdapter.swapCursor(cursor);
if (mListAdapter.getCount() > 0) {
mViewFlipper.setDisplayedChild(0);
} else {
mViewFlipper.setDisplayedChild(1);
}
}
@Override
public void onLoaderReset(Loader<Cursor> cursorLoader) {
mListAdapter.changeCursor(null);
}
public interface ReposFragmentListener {
void onRepoNewRequest(int id);
void onRepoDeleteRequest(long id);
void onRepoEditRequest(long id);
}
}