package kr.kdev.dg1s.biowiki.ui.posts; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.res.Configuration; import android.os.Bundle; import android.support.v4.app.FragmentTransaction; import android.support.v4.app.ListFragment; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import org.xmlrpc.android.ApiHelper; import org.xmlrpc.android.ApiHelper.ErrorType; import java.util.List; import java.util.Vector; import kr.kdev.dg1s.biowiki.BioWiki; import kr.kdev.dg1s.biowiki.R; import kr.kdev.dg1s.biowiki.models.Blog; import kr.kdev.dg1s.biowiki.models.Post; import kr.kdev.dg1s.biowiki.models.PostsListPost; import kr.kdev.dg1s.biowiki.ui.PullToRefreshHelper; import kr.kdev.dg1s.biowiki.ui.PullToRefreshHelper.RefreshListener; import kr.kdev.dg1s.biowiki.ui.posts.adapters.PostsListAdapter; import kr.kdev.dg1s.biowiki.util.BWAlertDialogFragment; import kr.kdev.dg1s.biowiki.util.NetworkUtils; import kr.kdev.dg1s.biowiki.util.ToastUtils; import kr.kdev.dg1s.biowiki.util.Utils; import uk.co.senab.actionbarpulltorefresh.extras.actionbarsherlock.PullToRefreshLayout; public class PostsListFragment extends ListFragment implements BioWiki.OnPostUploadedListener { public static final int POSTS_REQUEST_COUNT = 20; private PullToRefreshHelper mPullToRefreshHelper; private OnPostSelectedListener mOnPostSelectedListener; private OnSinglePostLoadedListener mOnSinglePostLoadedListener; private PostsListAdapter mPostsListAdapter; private ApiHelper.FetchPostsTask mCurrentFetchPostsTask; private ApiHelper.FetchSinglePostTask mCurrentFetchSinglePostTask; private View mProgressFooterView; private boolean mCanLoadMorePosts = true; private boolean mIsPage, mShouldSelectFirstPost, mIsFetchingPosts; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); Bundle extras = getActivity().getIntent().getExtras(); if (extras != null) { mIsPage = extras.getBoolean(PostsActivity.EXTRA_VIEW_PAGES); } } @Override public void onConfigurationChanged(Configuration newConfig) { boolean isRefreshing = mPullToRefreshHelper.isRefreshing(); super.onConfigurationChanged(newConfig); // Pull to refresh layout is destroyed onDetachedFromWindow, // so we have to re-init the layout, via the helper here initPullToRefreshHelper(); mPullToRefreshHelper.setRefreshing(isRefreshing); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.post_listview, container, false); } private void initPullToRefreshHelper() { mPullToRefreshHelper = new PullToRefreshHelper( getActivity(), (PullToRefreshLayout) getActivity().findViewById(R.id.ptr_layout), new RefreshListener() { @Override public void onRefreshStarted(View view) { if (getActivity() == null || !NetworkUtils.checkConnection(getActivity())) { mPullToRefreshHelper.setRefreshing(false); return; } refreshPosts((PostsActivity) getActivity()); } }, LinearLayout.class ); } private void refreshPosts(PostsActivity postsActivity) { Blog currentBlog = BioWiki.getCurrentBlog(); boolean hasLocalChanges = BioWiki.wpDB.findLocalChanges(currentBlog.getLocalTableBlogId(), mIsPage); if (hasLocalChanges) { AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(postsActivity); dialogBuilder.setTitle(getResources().getText(R.string.local_changes)); dialogBuilder.setMessage(getResources().getText(R.string.remote_changes)); dialogBuilder.setPositiveButton(getResources().getText(R.string.yes), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { mPullToRefreshHelper.setRefreshing(true); requestPosts(false); } } ); dialogBuilder.setNegativeButton(getResources().getText(R.string.no), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { mPullToRefreshHelper.setRefreshing(false); } }); dialogBuilder.setCancelable(true); dialogBuilder.create().show(); } else { mPullToRefreshHelper.setRefreshing(true); requestPosts(false); } } public PostsListAdapter getPostListAdapter() { if (mPostsListAdapter == null) { PostsListAdapter.OnLoadMoreListener loadMoreListener = new PostsListAdapter.OnLoadMoreListener() { @Override public void onLoadMore() { if (mCanLoadMorePosts && !mIsFetchingPosts) requestPosts(true); } }; PostsListAdapter.OnPostsLoadedListener postsLoadedListener = new PostsListAdapter.OnPostsLoadedListener() { @Override public void onPostsLoaded(int postCount) { if (postCount == 0 && mCanLoadMorePosts) { // No posts, let's request some requestPosts(false); setRefreshing(true); } else if (mShouldSelectFirstPost) { // Select the first row on a tablet, if requested mShouldSelectFirstPost = false; if (mPostsListAdapter.getCount() > 0) { PostsListPost postsListPost = (PostsListPost) mPostsListAdapter.getItem(0); if (postsListPost != null) { showPost(postsListPost.getPostId()); getListView().setItemChecked(0, true); } } } else if (Utils.isTablet()) { // Reload the last selected position, if available int selectedPosition = getListView().getCheckedItemPosition(); if (selectedPosition != ListView.INVALID_POSITION && selectedPosition < mPostsListAdapter.getCount()) { PostsListPost postsListPost = (PostsListPost) mPostsListAdapter.getItem(selectedPosition); if (postsListPost != null) { showPost(postsListPost.getPostId()); } } } } }; mPostsListAdapter = new PostsListAdapter(getActivity(), mIsPage, loadMoreListener, postsLoadedListener); } return mPostsListAdapter; } @Override public void onActivityCreated(Bundle bundle) { super.onActivityCreated(bundle); getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE); mProgressFooterView = View.inflate(getActivity(), R.layout.list_footer_progress, null); getListView().addFooterView(mProgressFooterView, null, false); mProgressFooterView.setVisibility(View.GONE); getListView().setDivider(getResources().getDrawable(R.drawable.list_divider)); getListView().setDividerHeight(1); getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() { public void onItemClick(AdapterView<?> arg0, View v, int position, long id) { if (position >= getPostListAdapter().getCount()) //out of bounds return; if (v == null) //view is gone return; PostsListPost postsListPost = (PostsListPost) getPostListAdapter().getItem(position); if (postsListPost == null) return; if (!mIsFetchingPosts || isLoadingMorePosts()) { showPost(postsListPost.getPostId()); } else if (hasActivity()) { Toast.makeText(getActivity(), mIsPage ? R.string.loading_pages : R.string.loading_posts, Toast.LENGTH_SHORT).show(); } } }); TextView textView = (TextView) getActivity().findViewById(R.id.title_empty); if (textView != null) { if (mIsPage) { textView.setText(getText(R.string.pages_empty_list)); } else { textView.setText(getText(R.string.posts_empty_list)); } } initPullToRefreshHelper(); BioWiki.setOnPostUploadedListener(this); } public void onAttach(Activity activity) { super.onAttach(activity); try { // check that the containing activity implements our callback mOnPostSelectedListener = (OnPostSelectedListener) activity; mOnSinglePostLoadedListener = (OnSinglePostLoadedListener) activity; } catch (ClassCastException e) { activity.finish(); throw new ClassCastException(activity.toString() + " must implement Callback"); } } public void onResume() { super.onResume(); if (BioWiki.getCurrentBlog() != null) { if (getListView().getAdapter() == null) { getListView().setAdapter(getPostListAdapter()); } getPostListAdapter().loadPosts(); } } public boolean isRefreshing() { return mPullToRefreshHelper.isRefreshing(); } public void setRefreshing(boolean refreshing) { mPullToRefreshHelper.setRefreshing(refreshing); } private void showPost(long selectedId) { if (BioWiki.getCurrentBlog() == null) return; Post post = BioWiki.wpDB.getPostForLocalTablePostId(selectedId); if (post != null) { BioWiki.currentPost = post; mOnPostSelectedListener.onPostSelected(post); } else { if (!getActivity().isFinishing()) { FragmentTransaction ft = getFragmentManager().beginTransaction(); BWAlertDialogFragment alert = BWAlertDialogFragment.newAlertDialog(getString(R.string.post_not_found)); ft.add(alert, "alert"); ft.commitAllowingStateLoss(); } } } public boolean isLoadingMorePosts() { return mIsFetchingPosts && (mProgressFooterView != null && mProgressFooterView.getVisibility() == View.VISIBLE); } public void requestPosts(boolean loadMore) { if (!hasActivity() || BioWiki.getCurrentBlog() == null || mIsFetchingPosts) return; if (!NetworkUtils.checkConnection(getActivity())) return; int postCount = getPostListAdapter().getRemotePostCount() + POSTS_REQUEST_COUNT; if (!loadMore) { mCanLoadMorePosts = true; postCount = POSTS_REQUEST_COUNT; } List<Object> apiArgs = new Vector<Object>(); apiArgs.add(BioWiki.getCurrentBlog()); apiArgs.add(mIsPage); apiArgs.add(postCount); apiArgs.add(loadMore); if (mProgressFooterView != null && loadMore) { mProgressFooterView.setVisibility(View.VISIBLE); } mCurrentFetchPostsTask = new ApiHelper.FetchPostsTask(new ApiHelper.FetchPostsTask.Callback() { @Override public void onSuccess(int postCount) { mCurrentFetchPostsTask = null; mIsFetchingPosts = false; if (!hasActivity()) return; mPullToRefreshHelper.setRefreshing(false); if (mProgressFooterView != null) { mProgressFooterView.setVisibility(View.GONE); } if (postCount == 0) { mCanLoadMorePosts = false; } else if (postCount == getPostListAdapter().getRemotePostCount() && postCount != POSTS_REQUEST_COUNT) { mCanLoadMorePosts = false; } getPostListAdapter().loadPosts(); } @Override public void onFailure(ApiHelper.ErrorType errorType, String errorMessage, Throwable throwable) { mCurrentFetchPostsTask = null; mIsFetchingPosts = false; if (!hasActivity()) { return; } mPullToRefreshHelper.setRefreshing(false); if (mProgressFooterView != null) { mProgressFooterView.setVisibility(View.GONE); } if (errorType != ErrorType.TASK_CANCELLED) { ToastUtils.showToast(getActivity(), mIsPage ? R.string.error_refresh_pages : R.string.error_refresh_posts, ToastUtils.Duration.LONG); } } }); mIsFetchingPosts = true; mCurrentFetchPostsTask.execute(apiArgs); } protected void clear() { if (getPostListAdapter() != null) { getPostListAdapter().clear(); } mCanLoadMorePosts = true; if (mProgressFooterView != null && mProgressFooterView.getVisibility() == View.VISIBLE) { mProgressFooterView.setVisibility(View.GONE); } } public void setShouldSelectFirstPost(boolean shouldSelect) { mShouldSelectFirstPost = shouldSelect; } private boolean hasActivity() { return getActivity() != null; } @Override public void OnPostUploaded(String postId) { if (!hasActivity()) return; if (!NetworkUtils.checkConnection(getActivity())) { mPullToRefreshHelper.setRefreshing(false); return; } // Fetch the newly uploaded post if (!TextUtils.isEmpty(postId)) { List<Object> apiArgs = new Vector<Object>(); apiArgs.add(BioWiki.getCurrentBlog()); apiArgs.add(postId); apiArgs.add(mIsPage); mCurrentFetchSinglePostTask = new ApiHelper.FetchSinglePostTask(new ApiHelper.FetchSinglePostTask.Callback() { @Override public void onSuccess() { mCurrentFetchSinglePostTask = null; mIsFetchingPosts = false; if (!hasActivity()) { return; } mPullToRefreshHelper.setRefreshing(false); getPostListAdapter().loadPosts(); mOnSinglePostLoadedListener.onSinglePostLoaded(); } @Override public void onFailure(ApiHelper.ErrorType errorType, String errorMessage, Throwable throwable) { mCurrentFetchSinglePostTask = null; mIsFetchingPosts = false; if (!hasActivity()) { return; } if (errorType != ErrorType.TASK_CANCELLED) { ToastUtils.showToast(getActivity(), mIsPage ? R.string.error_refresh_pages : R.string.error_refresh_posts, ToastUtils.Duration.LONG); } mPullToRefreshHelper.setRefreshing(false); } }); mPullToRefreshHelper.setRefreshing(true); mIsFetchingPosts = true; mCurrentFetchSinglePostTask.execute(apiArgs); } } public void onBlogChanged() { if (mCurrentFetchPostsTask != null) { mCurrentFetchPostsTask.cancel(true); } if (mCurrentFetchSinglePostTask != null) { mCurrentFetchSinglePostTask.cancel(true); } mIsFetchingPosts = false; mPullToRefreshHelper.setRefreshing(false); } public interface OnPostSelectedListener { public void onPostSelected(Post post); } public interface OnPostActionListener { public void onPostAction(int action, Post post); } public interface OnSinglePostLoadedListener { public void onSinglePostLoaded(); } }