package org.zarroboogs.weibo.fragment.base; import org.zarroboogs.devutils.DevLog; import org.zarroboogs.msrl.widget.MaterialSwipeRefreshLayout; import org.zarroboogs.util.net.WeiboException; import org.zarroboogs.utils.Constants; import org.zarroboogs.weibo.BeeboApplication; import org.zarroboogs.weibo.R; import org.zarroboogs.weibo.activity.MainTimeLineActivity; import org.zarroboogs.weibo.activity.WriteWeiboWithAppSrcActivity; import org.zarroboogs.weibo.adapter.AbstractAppListAdapter; import org.zarroboogs.weibo.bean.AsyncTaskLoaderResult; import org.zarroboogs.weibo.bean.data.DataItem; import org.zarroboogs.weibo.bean.data.DataListItem; import org.zarroboogs.weibo.loader.AbstractAsyncNetRequestTaskLoader; import org.zarroboogs.weibo.loader.DummyLoader; import org.zarroboogs.weibo.setting.SettingUtils; import org.zarroboogs.weibo.support.asyncdrawable.TimeLineBitmapDownloader; import org.zarroboogs.weibo.support.lib.LongClickableLinkMovementMethod; import org.zarroboogs.weibo.support.utils.BundleArgsConstants; import org.zarroboogs.weibo.support.utils.Utility; import org.zarroboogs.weibo.support.utils.ViewUtility; import org.zarroboogs.weibo.widget.AutoScrollListView; import org.zarroboogs.weibo.widget.TopTipsView; import com.melnykov.fab.FloatingActionButton; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.support.v4.app.LoaderManager; import android.support.v4.content.Loader; import android.support.v7.widget.Toolbar; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; import android.view.ViewGroup; import android.widget.AbsListView; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.TextView; public abstract class AbsBaseTimeLineFragment<T extends DataListItem<?, ?>> extends BaseStateFragment { protected MaterialSwipeRefreshLayout mTimeLineSwipeRefreshLayout; protected AutoScrollListView mPullToRefreshListView; protected TextView empty; protected TopTipsView newMsgTipBar; protected BaseAdapter timeLineAdapter; public FloatingActionButton mFab; protected static final int DB_CACHE_LOADER_ID = 0; protected static final int NEW_MSG_LOADER_ID = 1; protected static final int OLD_MSG_LOADER_ID = 3; protected int savedCurrentLoadingMsgViewPositon = NO_SAVED_CURRENT_LOADING_MSG_VIEW_POSITION; public static final int NO_SAVED_CURRENT_LOADING_MSG_VIEW_POSITION = -1; private boolean mCanLoadOldData = true; protected void buildLayout(View view) { mTimeLineSwipeRefreshLayout = ViewUtility.findViewById(view, R.id.refresh_layout); mTimeLineSwipeRefreshLayout.setEnableSount(SettingUtils.getEnableSound()); mTimeLineSwipeRefreshLayout.setFooterView(R.layout.listview_footer); empty = ViewUtility.findViewById(view, R.id.empty); mPullToRefreshListView = ViewUtility.findViewById(view, R.id.listView); newMsgTipBar = ViewUtility.findViewById(view, R.id.tv_unread_new_message_count_tip_bar); getListView().setHeaderDividersEnabled(false); getListView().setScrollingCacheEnabled(false); dismissFooterView(); mFab = ViewUtility.findViewById(view, R.id.absTimeLineFab); mFab.attachToListView((AbsListView) ViewUtility.findViewById(view, R.id.listView)); mFab.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(getActivity(), WriteWeiboWithAppSrcActivity.class); intent.putExtra(BundleArgsConstants.ACCOUNT_EXTRA, BeeboApplication.getInstance().getAccountBean()); intent.putExtra(Constants.TOKEN, BeeboApplication.getInstance().getAccessToken()); intent.putExtra(Constants.ACCOUNT, BeeboApplication.getInstance().getAccountBean()); startActivity(intent); } }); mFab.setOnLongClickListener(new OnLongClickListener() { @Override public boolean onLongClick(View v) { Utility.stopListViewScrollingAndScrollToTop(getListView()); mTimeLineSwipeRefreshLayout.setRefreshing(true); loadNewMsg(); return true; } }); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.listview_layout, container, false); buildLayout(view); return view; } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); if (mTimeLineSwipeRefreshLayout != null) { mTimeLineSwipeRefreshLayout.setOnRefreshLoadMoreListener(onRefreshListener); mPullToRefreshListView.setOnScrollListener(listViewOnScrollListener); mPullToRefreshListView.setOnItemClickListener(listViewOnItemClickListener); } buildListAdapter(); if (savedInstanceState != null) { savedCurrentLoadingMsgViewPositon = savedInstanceState.getInt("savedCurrentLoadingMsgViewPositon", NO_SAVED_CURRENT_LOADING_MSG_VIEW_POSITION); } } private Handler mHandler = new Handler(Looper.getMainLooper()); public void showMenuOnToolBar(final Toolbar toolbar, final int menuRes) { mHandler.postDelayed(new Runnable() { @Override public void run() { toolbar.getMenu().clear(); toolbar.inflateMenu(menuRes); } }, 200); } public MaterialSwipeRefreshLayout getSwipeRefreshLayout() { return this.mTimeLineSwipeRefreshLayout; } public AutoScrollListView getListView() { return mPullToRefreshListView; } public BaseAdapter getAdapter() { return timeLineAdapter; } public TopTipsView getNewMsgTipBar() { return newMsgTipBar; } public abstract T getDataList(); protected abstract void onTimeListViewItemClick(AdapterView<?> parent, View view, int position, long id); public void loadNewMsg() { mCanLoadOldData = true; getLoaderManager().destroyLoader(OLD_MSG_LOADER_ID); dismissFooterView(); getLoaderManager().restartLoader(NEW_MSG_LOADER_ID, null, msgAsyncTaskLoaderCallback); } protected void loadOldMsg(View view) { if (getLoaderManager().getLoader(OLD_MSG_LOADER_ID) != null || !mCanLoadOldData) { return; } getLoaderManager().destroyLoader(NEW_MSG_LOADER_ID); getLoaderManager().restartLoader(OLD_MSG_LOADER_ID, null, msgAsyncTaskLoaderCallback); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putInt("savedCurrentLoadingMsgViewPositon", savedCurrentLoadingMsgViewPositon); } private MaterialSwipeRefreshLayout.OnRefreshLoadMoreListener onRefreshListener = new MaterialSwipeRefreshLayout.OnRefreshLoadMoreListener() { @Override public void onRefresh() { if (getActivity() == null) { return; } if (getLoaderManager().getLoader(NEW_MSG_LOADER_ID) != null) { return; } loadNewMsg(); } @Override public void onLoadMore() { DevLog.printLog("TimeLineLoadMore ", "loadMore"); if (getActivity() == null) { return; } if (getLoaderManager().getLoader(OLD_MSG_LOADER_ID) != null) { return; } loadOldMsg(null); } }; private AdapterView.OnItemClickListener listViewOnItemClickListener = new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { getListView().clearChoices(); int headerViewsCount = getListView().getHeaderViewsCount(); if (isPositionBetweenHeaderViewAndFooterView(position)) { int indexInDataSource = position - headerViewsCount; DataItem msg = getDataList().getItem(indexInDataSource); if (!isNullFlag(msg)) { onTimeListViewItemClick(parent, view, indexInDataSource, id); } } else if (isLastItem(position)) { loadOldMsg(view); } } boolean isPositionBetweenHeaderViewAndFooterView(int position) { return position - getListView().getHeaderViewsCount() < getDataList().getSize() && position - getListView().getHeaderViewsCount() >= 0; } boolean isNullFlag(DataItem msg) { return msg == null; } boolean isLastItem(int position) { return position - 1 >= getDataList().getSize(); } }; private AbsListView.OnScrollListener listViewOnScrollListener = new AbsListView.OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { switch (scrollState) { case AbsListView.OnScrollListener.SCROLL_STATE_IDLE: if (!enableRefreshTime) { enableRefreshTime = true; getAdapter().notifyDataSetChanged(); } onListViewScrollStop(); LongClickableLinkMovementMethod.getInstance().setLongClickable(true); TimeLineBitmapDownloader.getInstance().setPauseDownloadWork(false); TimeLineBitmapDownloader.getInstance().setPauseReadWork(false); break; case AbsListView.OnScrollListener.SCROLL_STATE_FLING: enableRefreshTime = false; LongClickableLinkMovementMethod.getInstance().setLongClickable(false); TimeLineBitmapDownloader.getInstance().setPauseDownloadWork(true); TimeLineBitmapDownloader.getInstance().setPauseReadWork(true); onListViewScrollStateFling(); break; case AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL: enableRefreshTime = true; LongClickableLinkMovementMethod.getInstance().setLongClickable(false); TimeLineBitmapDownloader.getInstance().setPauseDownloadWork(true); onListViewScrollStateTouchScroll(); break; } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { onListViewScroll(); } }; @Override public void onPause() { super.onPause(); TimeLineBitmapDownloader.getInstance().setPauseDownloadWork(false); TimeLineBitmapDownloader.getInstance().setPauseReadWork(false); } protected void onListViewScrollStop() { } protected void onListViewScrollStateTouchScroll() { } protected void onListViewScrollStateFling() { } protected void onListViewScroll() { if (allowLoadOldMsgBeforeReachListBottom() && getListView().getLastVisiblePosition() > 7 && getListView().getLastVisiblePosition() > getDataList().getSize() - 3 && getListView().getFirstVisiblePosition() != getListView().getHeaderViewsCount()) { loadOldMsg(null); } } protected boolean allowLoadOldMsgBeforeReachListBottom() { return true; } protected void showFooterView() { } protected void dismissFooterView() { } protected void showErrorFooterView() { } protected abstract void buildListAdapter(); protected boolean allowRefresh() { boolean isNewMsgLoaderLoading = getLoaderManager().getLoader(NEW_MSG_LOADER_ID) != null; return getListView().getVisibility() == View.VISIBLE && !isNewMsgLoaderLoading; } @Override public void onResume() { super.onResume(); getListView().setFastScrollEnabled(SettingUtils.allowFastScroll()); getAdapter().notifyDataSetChanged(); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); Loader<T> loader = getLoaderManager().getLoader(NEW_MSG_LOADER_ID); if (loader != null) { getLoaderManager().initLoader(NEW_MSG_LOADER_ID, null, msgAsyncTaskLoaderCallback); } loader = getLoaderManager().getLoader(OLD_MSG_LOADER_ID); if (loader != null) { getLoaderManager().initLoader(OLD_MSG_LOADER_ID, null, msgAsyncTaskLoaderCallback); } if (getActivity() instanceof MainTimeLineActivity) { mFab.setVisibility(View.VISIBLE); } else { if (mFab != null) { mFab.setVisibility(View.GONE); } } } protected void showListView() { } private volatile boolean enableRefreshTime = true; public boolean isListViewFling() { return !enableRefreshTime; } protected abstract void onNewMsgLoaderSuccessCallback(T newValue, Bundle loaderArgs); protected abstract void onOldMsgLoaderSuccessCallback(T newValue); protected void onOldMsgLoaderFailedCallback(WeiboException exception) { } protected void onNewMsgLoaderFailedCallback(WeiboException exception) { } private Loader<AsyncTaskLoaderResult<T>> createNewMsgLoader(int id, Bundle args) { Loader<AsyncTaskLoaderResult<T>> loader = onCreateNewMsgLoader(id, args); if (loader == null) { loader = new DummyLoader<T>(getActivity()); } if (loader instanceof AbstractAsyncNetRequestTaskLoader) { ((AbstractAsyncNetRequestTaskLoader<T>) loader).setArgs(args); } return loader; } private Loader<AsyncTaskLoaderResult<T>> createOldMsgLoader(int id, Bundle args) { Loader<AsyncTaskLoaderResult<T>> loader = onCreateOldMsgLoader(id, args); if (loader == null) { loader = new DummyLoader<T>(getActivity()); } return loader; } protected Loader<AsyncTaskLoaderResult<T>> onCreateNewMsgLoader(int id, Bundle args) { return null; } protected Loader<AsyncTaskLoaderResult<T>> onCreateOldMsgLoader(int id, Bundle args) { return null; } protected LoaderManager.LoaderCallbacks<AsyncTaskLoaderResult<T>> msgAsyncTaskLoaderCallback = new LoaderManager.LoaderCallbacks<AsyncTaskLoaderResult<T>>() { @Override public Loader<AsyncTaskLoaderResult<T>> onCreateLoader(int id, Bundle args) { showListView(); switch (id) { case NEW_MSG_LOADER_ID: if (args == null || args.getBoolean(BundleArgsConstants.SCROLL_TO_TOP)) { Utility.stopListViewScrollingAndScrollToTop(getListView()); } return createNewMsgLoader(id, args); case OLD_MSG_LOADER_ID: showFooterView(); return createOldMsgLoader(id, args); } return null; } public static final boolean isDebug = false; @Override public void onLoadFinished(Loader<AsyncTaskLoaderResult<T>> loader, AsyncTaskLoaderResult<T> result) { T data = result != null ? result.data : null; WeiboException exception = result != null ? result.exception : null; Bundle args = result != null ? result.args : null; switch (loader.getId()) { case NEW_MSG_LOADER_ID: mTimeLineSwipeRefreshLayout.setRefreshing(false); if (Utility.isAllNotNull(exception)) { if (isDebug || !exception.getError().trim().equals("用户请求超过上限")) { newMsgTipBar.setError(exception.getError()); } onNewMsgLoaderFailedCallback(exception); } else { onNewMsgLoaderSuccessCallback(data, args); } break; case OLD_MSG_LOADER_ID: if (exception != null) { showErrorFooterView(); onOldMsgLoaderFailedCallback(exception); } else if (data != null) { mCanLoadOldData = data.getSize() > 1; onOldMsgLoaderSuccessCallback(data); getAdapter().notifyDataSetChanged(); dismissFooterView(); } else { mCanLoadOldData = false; dismissFooterView(); } break; } getLoaderManager().destroyLoader(loader.getId()); } @Override public void onLoaderReset(Loader<AsyncTaskLoaderResult<T>> loader) { } }; }