package com.mobidev.newsapp.ui.fragments; import android.app.Activity; import android.app.ProgressDialog; import android.content.ContentResolver; import android.content.ContentValues; import android.database.ContentObserver; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.provider.BaseColumns; import android.support.v4.app.Fragment; 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.SwipeRefreshLayout; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.animation.AnimationUtils; import android.widget.AbsListView; import android.widget.AdapterView; import android.widget.ListView; import android.widget.Toast; import com.android.volley.AuthFailureError; import com.android.volley.NetworkError; import com.android.volley.NoConnectionError; import com.android.volley.ParseError; import com.android.volley.Request; import com.android.volley.Response; import com.android.volley.ServerError; import com.android.volley.TimeoutError; import com.android.volley.VolleyError; import com.android.volley.toolbox.JsonObjectRequest; import com.mobidev.newsapp.adapter.NewsCursorAdapter; import com.mobidev.newsapp.ui.widgets.StaggeredGridView; import com.mobidev.newsapp.utils.ParserUtils; import com.mobidev.newsapp.R; import com.mobidev.newsapp.VolleySingleton; import com.mobidev.newsapp.database.AppContract; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.util.ArrayList; import java.util.HashMap; import java.util.Locale; import java.util.Map; /** * Created by lawrence on 4/24/15. */ public class NewsListFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> { private static final String ARG_NEWS_TYPE = "news_type_id"; private static final String LOADER_ARG_TAG = "news_type"; private static final String requestUrl = "http://testing.mlab-training.devs.mobi/php_news_api/news.php"; private String tag_json_obj = "request_news_list"; private NewsCursorAdapter mAdapter; private int news_type_id; private ProgressDialog mProgress; boolean mListShown; private View mProgressContainer; private View mListContainer; private SwipeRefreshLayout swipeContainer; private ListView lv; private StaggeredGridView mGridView; private OnNewsItemSelectedListener itemSelectedListener; private ContentResolver cr = null; public static NewsListFragment newInstance(int news_type_id) { NewsListFragment fragment = new NewsListFragment(); Bundle b = new Bundle(); b.putInt(ARG_NEWS_TYPE, news_type_id); fragment.setArguments(b); return fragment; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_news_headlines, container, false); swipeContainer = (SwipeRefreshLayout) rootView .findViewById(R.id.swipeProjectsContainer); lv = (ListView) rootView.findViewById(R.id.list); mGridView = (StaggeredGridView) rootView.findViewById(R.id.grid_view); if (mGridView == null) { lv.setOnScrollListener(new AbsListView.OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { int topRowVerticalPosition = (lv == null || lv .getChildCount() == 0) ? 0 : lv.getChildAt(0) .getTop(); swipeContainer.setEnabled(topRowVerticalPosition >= 0); } }); // int INTERNAL_EMPTY_ID = 0x00ff0001; // (rootView.findViewById(android.R.id.empty)) // .setId(INTERNAL_EMPTY_ID); mAdapter = new NewsCursorAdapter( getActivity().getApplicationContext(), null, 0); lv.setAdapter(mAdapter); lv.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { if (itemSelectedListener != null) { itemSelectedListener.onNewsItemSelected(position, news_type_id); } } }); } else { mAdapter = new NewsCursorAdapter( getActivity().getApplicationContext(), null, 0); mGridView.setAdapter(mAdapter); mGridView.setOnItemClickListener(new StaggeredGridView.OnItemClickListener() { @Override public void onItemClick(StaggeredGridView parent, View view, int position, long id) { if (itemSelectedListener != null) { itemSelectedListener.onNewsItemSelected(position, news_type_id); } } }); } swipeContainer.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { fetchNews(news_type_id); } }); swipeContainer.setColorSchemeResources(R.color.google_green, R.color.google_blue, R.color.google_red, R.color.google_orange); mListContainer = rootView.findViewById(R.id.listContainer); mProgressContainer = rootView.findViewById(R.id.progressContainer); mListShown = true; return rootView; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); setHasOptionsMenu(true); news_type_id = getArguments().getInt(ARG_NEWS_TYPE); setListShown(false); Bundle args = new Bundle(); args.putInt(LOADER_ARG_TAG, news_type_id); getLoaderManager().initLoader(NewsQuery._TOKEN, args, this); } @Override public void onAttach(Activity activity) { super.onAttach(activity); super.onAttach(activity); try { itemSelectedListener = (OnNewsItemSelectedListener) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement OnTutSelectedListener"); } cr = getActivity().getContentResolver(); } // @Override // public void onListItemClick(ListView l, View v, int position, long id) { // if (itemSelectedListener != null) { // itemSelectedListener.onNewsItemSelected(position, news_type_id); // } // } @Override public Loader<Cursor> onCreateLoader(int token, Bundle bundle) { Loader<Cursor> loader = null; if (token == NewsQuery._TOKEN) { int newstype = bundle.getInt(LOADER_ARG_TAG); ArrayList<String> selectionArgs = new ArrayList<String>(); ArrayList<String> selectionClauses = new ArrayList<String>(); if (newstype > 0) { selectionClauses.add(AppContract.News.NEWS_TYPE_ID + "=?"); selectionArgs.add(String.format(Locale.US, "%d", newstype)); } String selection = selectionClauses.isEmpty() ? null : ParserUtils .joinStrings(" AND ", selectionClauses, null); String[] args = selectionArgs.isEmpty() ? null : selectionArgs .toArray(new String[0]); return new CursorLoader( getActivity().getApplicationContext(), AppContract.News.CONTENT_URI, NewsQuery.PROJECTION, selection, args, AppContract.News.DEFAULT_SORT); } return null; } @Override public void onLoadFinished(Loader<Cursor> loader, Cursor data) { int token = loader.getId(); if (token == NewsQuery._TOKEN) { if (data.getCount() == 0) { fetchNews(news_type_id); } mAdapter.swapCursor(data); } if (isResumed()) { setListShown(true); } else { setListShownNoAnimation(true); } } @Override public void onLoaderReset(Loader<Cursor> loader) { mAdapter.swapCursor(null); } private void fetchNews(int universityId) { Uri.Builder builder = Uri.parse(requestUrl).buildUpon(); builder.appendQueryParameter("news_type_id", Integer.toString(universityId)); // http://testing.mlab-training.devs.mobi/php_list_db_example/universityinfo.php?university_id=2 JsonObjectRequest jsonObjReq = new JsonObjectRequest(Request.Method.GET, builder.toString(), new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { if (response.length() > 0) {//checking if response is null try { JSONArray unisArray = response.getJSONArray("news"); System.err.println(">>>> " + unisArray); for (int i = 0; i < unisArray.length(); i++) { JSONObject news_item = unisArray.getJSONObject(i); ContentValues mNewValues = new ContentValues(); mNewValues.put(AppContract.NewsColumns.NEWS_ID, news_item.getInt("id")); mNewValues.put(AppContract.NewsColumns.NEWS_TYPE_ID, news_item.getInt("news_type")); mNewValues.put(AppContract.NewsColumns.SLUG, news_item.getString("slug")); mNewValues.put(AppContract.NewsColumns.TITLE, news_item.getString("title")); mNewValues.put(AppContract.NewsColumns.CONTENT, news_item.getString("content")); mNewValues.put(AppContract.NewsColumns.IMAGE_URL, news_item.getString("image_url")); mNewValues.put(AppContract.NewsColumns.CREATED_AT, news_item.getString("created_at")); Uri mNewUri = cr .insert(AppContract.News.CONTENT_URI, mNewValues); cr.registerContentObserver( mNewUri, true, new MyContentObserver(new Handler())); } } catch (JSONException e) { e.printStackTrace(); } swipeContainer.setRefreshing(false); } else { if (swipeContainer.isShown()) { swipeContainer.setRefreshing(false); } try { Toast.makeText(getActivity(), "Sorry! No results found", Toast.LENGTH_LONG) .show(); } catch (NullPointerException npe) { System.out.println(npe); } } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { if (error instanceof NetworkError) { try { Toast.makeText(getActivity(), "Network Error. Try Again Later", Toast.LENGTH_SHORT).show(); } catch (NullPointerException npe) { System.err.println(npe); } } else if (error instanceof ServerError) { try { Toast.makeText( getActivity(), "Problem Connecting to Server. Try Again Later", Toast.LENGTH_SHORT).show(); } catch (NullPointerException npe) { System.err.println(npe); } } else if (error instanceof AuthFailureError) { } else if (error instanceof ParseError) { } else if (error instanceof NoConnectionError) { try { Toast.makeText(getActivity(), "No Connection", Toast.LENGTH_SHORT).show(); } catch (NullPointerException npe) { System.err.println(npe); } } else if (error instanceof TimeoutError) { try { Toast.makeText( getActivity().getApplicationContext(), "Timeout Error. Try Again Later", Toast.LENGTH_SHORT).show(); } catch (NullPointerException npe) { System.err.println(npe); } } if (swipeContainer.isShown()) { swipeContainer.setRefreshing(false); } } }) { @Override public Map<String, String> getHeaders() throws AuthFailureError { Map<String, String> params = new HashMap<String, String>(); params.put("Accept", "application/json"); return params; } }; // Adding request to request queue VolleySingleton.getInstance().addToRequestQueue(jsonObjReq, tag_json_obj); } /** * @param shown * @param animate * @see http * ://stackoverflow.com/questions/12869779/error-using-setlistshown * -on-a-listfragment-with-a-custom-view?answertab=active#tab-top */ public void setListShown(boolean shown, boolean animate) { if (mListShown == shown) { return; } mListShown = shown; if (shown) { if (animate) { mProgressContainer.startAnimation(AnimationUtils .loadAnimation(getActivity(), android.R.anim.fade_out)); mListContainer.startAnimation(AnimationUtils.loadAnimation( getActivity(), android.R.anim.fade_in)); } mProgressContainer.setVisibility(View.GONE); mListContainer.setVisibility(View.VISIBLE); } else { if (animate) { mProgressContainer.startAnimation(AnimationUtils .loadAnimation(getActivity(), android.R.anim.fade_in)); mListContainer.startAnimation(AnimationUtils.loadAnimation( getActivity(), android.R.anim.fade_out)); } mProgressContainer.setVisibility(View.VISIBLE); mListContainer.setVisibility(View.INVISIBLE); } } public void setListShown(boolean shown) { setListShown(shown, true); } public void setListShownNoAnimation(boolean shown) { setListShown(shown, false); } class MyContentObserver extends ContentObserver { /** * Creates a content observer. * * @param handler The handler to run {@link #onChange} on, or null if none. */ public MyContentObserver(Handler handler) { super(handler); } @Override public boolean deliverSelfNotifications() { return true; } @Override public void onChange(boolean selfChange) { super.onChange(selfChange); } } public interface OnNewsItemSelectedListener { public void onNewsItemSelected(int itemId, int news_type_id); } private interface NewsQuery { int _TOKEN = 0x1; String[] PROJECTION = {BaseColumns._ID, AppContract.NewsColumns.NEWS_ID, AppContract.NewsColumns.TITLE, AppContract.NewsColumns.IMAGE_URL, AppContract.NewsColumns.CREATED_AT}; } }