package com.abewy.android.apps.klyph.fragment; import java.util.List; import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.animation.AnimationUtils; import android.widget.AbsListView; import android.widget.AbsListView.OnScrollListener; import android.widget.ListAdapter; import com.abewy.android.apps.klyph.R; import com.abewy.android.apps.klyph.adapter.MultiObjectAdapter; import com.abewy.android.apps.klyph.core.graph.GraphObject; import com.abewy.android.apps.klyph.core.request.RequestError; import com.abewy.android.apps.klyph.core.request.Response; import com.abewy.android.apps.klyph.request.AsyncRequest; import com.abewy.android.apps.klyph.request.AsyncRequest.Query; import com.abewy.android.apps.klyph.view.ListEmptyView; import com.abewy.app.BaseDialogListFragment; import com.abewy.klyph.items.Progress; import com.abewy.klyph.items.TextButtonItem; import com.abewy.net.ConnectionState; public class KlyphDialogFragment extends BaseDialogListFragment implements OnScrollListener { private final String TAG = "KlyphDialogFragment " + this.getClass().getSimpleName(); private AsyncRequest request; private boolean userScroll = false; private boolean loading = false; private boolean firstLoad = true; private boolean isError = false; private boolean viewDestroyed = false; private boolean noMoreData = false; private boolean loadingObjectAsFirstItem = false; private GraphObject loadingObject; private int emptyText; private int errorText = R.string.error; private View loadingView; private boolean listVisible = false; private int requestType; private String elementId; private String offset; private String initialOffset; @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); getListView().setOnScrollListener(this); getListView().setVisibility(View.GONE); ((View) getListView().getParent()).setVisibility(View.GONE); loadingView = view.findViewById(android.R.id.progress); defineEmptyView(); loadingObject = getLoadingObject(); loadingObject.setLoading(true); // setListVisible(false); // setEmptyViewVisible(false); } /** * Create, add and set the list empty view Override this method if you want * a custom empty view, or if you replaced listview by a gridview for * example */ protected void defineEmptyView() { ListEmptyView lev = new ListEmptyView(getActivity()); ((ViewGroup) getListView().getParent()).addView(lev); getListView().setEmptyView(lev); if (this.emptyText > 0) setEmptyText(emptyText); } public void setElementId(String id) { this.elementId = id; } public void setListAdapter(ListAdapter adapter) { getListView().setAdapter(adapter); } protected String getElementId() { return elementId; } protected void setOffset(String offset) { this.offset = offset; } protected void setInitialOffset(String offset) { this.initialOffset = offset; } protected void setRequestType(int requestType) { this.requestType = requestType; } protected void setNoMoreData(boolean noMoreData) { this.noMoreData = noMoreData; } protected void setLoadingObjectAsFirstItem(boolean loadingObjectAsFirstItem) { this.loadingObjectAsFirstItem = loadingObjectAsFirstItem; } private void setViewDestroyed(boolean viewDestroyed) { this.viewDestroyed = viewDestroyed; } protected boolean isViewDestroyed() { return viewDestroyed; } protected boolean isLoading() { return loading; } protected boolean isFirstLoad() { return firstLoad; } protected boolean hasNoMoreData() { return noMoreData; } protected boolean requestHasMoreData() { return request.hasMoreData(); } protected void defineEmptyText(int resId) { this.emptyText = resId; setEmptyText(resId); } protected void setEmptyText(int resId) { if (getListView().getEmptyView() != null) { ((ListEmptyView) getListView().getEmptyView()).setText(resId); } } protected void setErrorText(int resId) { this.errorText = resId; } public void load() { // Log.i(TAG, "load"); if ((isFirstLoad() && !isLoading()) || isViewDestroyed()) { setViewDestroyed(false); setOffset(initialOffset); setNoMoreData(false); firstLoad = true; refresh(); } } protected void refresh() { startLoading(); Log.d(TAG, "request = " + requestType + ", id = " + elementId + ", offset = " + offset); request = new AsyncRequest(requestType, elementId, offset, new AsyncRequest.Callback() { @Override public void onComplete(Response response) { Log.i(TAG, "onCompleted"); onRequestComplete(response); } }); request.execute(); } private void onRequestComplete(final Response response) { if (getActivity() != null) { getActivity().runOnUiThread(new Runnable() { @Override public void run() { if (response.getError() == null) { onRequestSuccess(response.getGraphObjectList()); } else { onRequestError(response.getError()); } } }); } } private void onRequestSuccess(List<GraphObject> result) { if (getView() != null) // Check if view is created populate(result); } private void onRequestError(RequestError error) { Log.i(TAG, "error " + error.toString()); if (getView() != null) { isError = true; loading = false; int errorText = this.errorText; if (!ConnectionState.getInstance(getActivity()).isOnline()) { errorText = R.string.request_connexion_error; } TextButtonItem errorItem = new TextButtonItem(); errorItem.setText(getString(errorText)); // TODO This is not a good copding practice ! errorItem.setButtonListener(new View.OnClickListener() { @Override public void onClick(View v) { retryRequestAfterError(); } }); getAdapter().add(errorItem); endLoading(); } } protected MultiObjectAdapter getAdapter() { return (MultiObjectAdapter) getListView().getAdapter(); } protected void populate(List<GraphObject> data) { for (GraphObject graphObject : data) { getAdapter().add(graphObject); } // adapter.addAll(data); is only available in api 11 // getAdapter().notifyDataSetChanged(); endLoading(); if (data.size() == 0 || (request != null && !request.hasMoreData())) noMoreData = true; else offset = String.valueOf(getAdapter().getCount()); } protected void startLoading() { loading = true; if (isError == true && getAdapter().getCount() > 0) { GraphObject lastObject = getAdapter().getLastItem(); if (lastObject instanceof TextButtonItem) { getAdapter().remove(lastObject); } } isError = false; if (!firstLoad) { if (!loadingObjectAsFirstItem) getAdapter().add(loadingObject); else getAdapter().insert(loadingObject, 0); getAdapter().notifyDataSetChanged(); } } protected void endLoading() { loading = false; firstLoad = false; getAdapter().remove(loadingObject); getAdapter().notifyDataSetChanged(); setLoadingViewVisible(false); setListVisible(true); } public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { if (userScroll) { if (!loading && !firstLoad && !noMoreData && !isError) { boolean loadMore = firstVisibleItem + visibleItemCount >= totalItemCount; if (loadMore) { // Log.i(TAG, "onScroll refresh"); refresh(); } } } } public void onScrollStateChanged(AbsListView view, int scrollState) { userScroll = scrollState != OnScrollListener.SCROLL_STATE_IDLE; } protected GraphObject getLoadingObject() { return new Progress(); } protected int getLayout() { return R.layout.list; } @Override protected void setListVisible(boolean visible) { setListVisibility(visible, true); } protected void setListVisible(boolean visible, boolean animate) { setListVisibility(visible, animate); } private void setListVisibility(boolean visible, boolean animate) { ensureList(); if (listVisible == visible) { return; } listVisible = visible; View parent = (View) getListView().getParent(); if (visible) { if (animate) { loadingView.startAnimation(AnimationUtils.loadAnimation(getActivity(), android.R.anim.fade_out)); parent.startAnimation(AnimationUtils.loadAnimation(getActivity(), android.R.anim.fade_in)); } else { loadingView.clearAnimation(); parent.clearAnimation(); } loadingView.setVisibility(View.GONE); parent.setVisibility(View.VISIBLE); } else { if (animate) { loadingView.startAnimation(AnimationUtils.loadAnimation(getActivity(), android.R.anim.fade_in)); parent.startAnimation(AnimationUtils.loadAnimation(getActivity(), android.R.anim.fade_out)); } else { loadingView.clearAnimation(); parent.clearAnimation(); } loadingView.setVisibility(View.VISIBLE); parent.setVisibility(View.GONE); } } protected void ensureList() { //getListView().setEmptyView(getView().findViewById(android.R.id.empty)); } @Override public void onPause() { super.onPause(); // Log.i(TAG, "onPause"); } @Override public void onStop() { super.onStop(); Log.i(TAG, "onStop"); } @Override public void onDestroyView() { super.onDestroyView(); setViewDestroyed(true); // Log.i(TAG, "onDestroyView"); } @Override public void onDestroy() { super.onDestroy(); request = null; loadingObject = null; loadingView = null; requestType = Query.NONE; Log.i(TAG, "onDestroy"); } @Override public void onDetach() { super.onDetach(); Log.i(TAG, "onDetach"); } @Override public void onStart() { super.onStart(); // Log.i(TAG, "onStart"); } @Override public void onResume() { super.onResume(); if (getAdapter() != null) { getAdapter().notifyDataSetChanged(); } } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); Log.i(TAG, "onSaveInstanceState"); } public void retryRequestAfterError() { Log.d(TAG, "retryRequestAfterError "); setEmptyText(emptyText); refresh(); } }