package com.ladjzero.uzlee; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener; import android.util.Log; import android.util.LruCache; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AbsListView; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; import com.alibaba.fastjson.JSON; import com.ladjzero.hipda.Thread; import com.ladjzero.hipda.Threads; import com.ladjzero.uzlee.utils.Utils; import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.listener.PauseOnScrollListener; import com.orhanobut.logger.Logger; import com.r0adkll.slidr.model.SlidrInterface; import com.rey.material.app.Dialog; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.Predicate; import org.apache.commons.collections.Transformer; import java.util.ArrayList; import java.util.Collection; import java.util.List; import butterknife.Bind; import butterknife.ButterKnife; import butterknife.OnClick; public abstract class FragmentThreadsAbs extends FragmentBase implements AdapterView.OnItemClickListener, SharedPreferences.OnSharedPreferenceChangeListener, AdapterView.OnItemLongClickListener, ActivityBase.OnToolbarClickListener { private static final String TAG = "FragmentThreadsAbs"; protected Threads mThreads; protected AdapterThreads mAdapter; @Bind(R.id.thread_swipe) SwipeRefreshLayout mSwipe; @Bind(R.id.threads) ListView listView; private ActivityBase mActivity; private boolean mEnablePullToRefresh; private SlidrInterface slidrInterface; private OnScrollUpOrDown mOnScrollUpOrDown; protected final Model model = new Model(); @OnClick(R.id.toLogin) void login() { Utils.replaceActivity(getActivity(), ActivityLogin.class); } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if (mAdapter != null && ("font_size".equals(key) || "highlight_unread".equals(key))) { mAdapter.notifyDataSetChanged(); } } public void setScrollUpOrDownListener(OnScrollUpOrDown onScrollUpOrDown) { this.mOnScrollUpOrDown = onScrollUpOrDown; } public abstract int layout(); @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); LruCache<String, String> cache = App.getInstance().getMemCache(); String cached = cache.get(keyOfThreadsToCache()); List<Thread> threads = null; try { threads = JSON.parseArray(cached, Thread.class); } catch (Exception e) { e.printStackTrace(); } mThreads = new Threads(); if (threads != null) { mThreads.addAll(threads); } } protected void onListViewReady(ListView listView, LayoutInflater inflater) {}; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mActivity = (ActivityBase) getActivity(); Bundle args = getArguments(); mEnablePullToRefresh = args.getBoolean("enablePullToRefresh", true); View rootView = inflater.inflate(layout(), container, false); ButterKnife.bind(this, rootView); onListViewReady(listView, inflater); if (this instanceof OnRefreshListener) { mSwipe.setOnRefreshListener((OnRefreshListener) this); } mSwipe.setProgressBackgroundColorSchemeColor(Utils.getThemeColor(mActivity, R.attr.colorTextInverse)); int primaryColor = Utils.getThemeColor(mActivity, R.attr.colorPrimary); mSwipe.setColorSchemeColors(primaryColor, primaryColor, primaryColor, primaryColor); // mSwipe.setProgressViewOffset(false, -Utils.dp2px(mActivity, 12), Utils.dp2px(mActivity, 60)); Logger.i("enable pull to fresh %b", mEnablePullToRefresh); mSwipe.setEnabled(mEnablePullToRefresh); if (mActivity instanceof ActivityUserThreads) { slidrInterface = ((ActivityUserThreads) mActivity).getSlidrInterface(); } else if (mActivity instanceof ActivitySearch) { slidrInterface = ((ActivitySearch) mActivity).getSlidrInterface(); } mAdapter = new AdapterThreads(mActivity, mThreads); listView.setAdapter(mAdapter); listView.setOnItemClickListener(this); // if (mDataSource != DATA_SOURCE_THREADS) { // listView.setPadding(0, 0, 0, 0); // } listView.setOnScrollListener( new PauseOnScrollListener(ImageLoader.getInstance(), true, true, new DirectionDetectScrollListener())); mActivity.getSettings() .registerOnSharedPreferenceChangeListener(this); listView.setOnItemLongClickListener(this); registerForContextMenu(listView); return rootView; } @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { final Thread thread = (Thread) parent.getItemAtPosition(position); final Dialog dialog = new Dialog(mActivity); View v = LayoutInflater.from(getActivity()).inflate(R.layout.threads_actions_dialog, null); ListView listView = (ListView) v.findViewById(R.id.actions); listView.setDivider(null); listView.setAdapter(new ArrayAdapter<>(mActivity, R.layout.list_item_of_dialog, R.id.text, new String[]{"复制标题", "查看最新回复"})); dialog.negativeActionClickListener(new View.OnClickListener() { @Override public void onClick(View v) { dialog.dismiss(); } }); dialog.title("") .titleColor(Utils.getThemeColor(mActivity, R.attr.colorText)) .backgroundColor(Utils.getThemeColor(mActivity, android.R.attr.colorBackground)) .contentView(v) .show(); listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { switch (position) { case 0: ClipboardManager clipboardManager = (ClipboardManager) mActivity.getSystemService(Context.CLIPBOARD_SERVICE); StringBuilder builder = new StringBuilder(); ClipData clipData = ClipData.newPlainText("post content", thread.getTitle()); clipboardManager.setPrimaryClip(clipData); mActivity.showToast("复制到剪切版"); break; case 1: Intent intent = new Intent(mActivity, ActivityPosts.class); intent.putExtra("tid", thread.getId()); intent.putExtra("page", 9999); intent.putExtra("title", thread.getTitle()); intent.putExtra("uid", thread.getAuthor().getId()); startActivity(intent); } dialog.dismiss(); } }); return true; } @Override public void onDestroyView() { LruCache<String, String> cache = App.getInstance().getMemCache(); String toCache = JSON.toJSONString(mThreads); if (toCache != null) { cache.put(keyOfThreadsToCache(), toCache); } mActivity.getSettings() .unregisterOnSharedPreferenceChangeListener(this); unregisterForContextMenu(listView); super.onDestroyView(); } @Override public void onResume() { super.onResume(); mAdapter.notifyDataSetChanged(); mSwipe.setEnabled(mEnablePullToRefresh); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); if (mThreads != null) { ArrayList<Integer> ids = new ArrayList<Integer>(); for (Thread t : mThreads) { ids.add(t.getId()); } outState.putIntegerArrayList("ids", ids); } outState.putInt("index", listView.getFirstVisiblePosition()); View v = listView.getChildAt(0); outState.putInt("top", v == null ? 0 : v.getTop()); } @Override public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { Thread t = (Thread) adapterView.getAdapter().getItem(i); t.setNew(false); Intent intent = new Intent(mActivity, ActivityPosts.class); intent.putExtra("fid", getArguments().getInt("fid")); intent.putExtra("tid", t.getId()); intent.putExtra("title", t.getTitle()); intent.putExtra("pid", t.getToFind()); intent.putExtra("uid", t.getAuthor().getId()); startActivity(intent); } public void onThreads(Threads threads) { mThreads.setMeta(threads.getMeta()); if (threads.size() != 0) { if (threads.getMeta().getPage() == 1) { mThreads.clear(); } final Collection<Integer> ids = CollectionUtils.collect(mThreads, new Transformer() { @Override public Object transform(Object o) { return ((Thread) o).getId(); } }); mThreads.addAll(CollectionUtils.selectRejected(threads, new Predicate() { @Override public boolean evaluate(Object o) { return ids.contains(((Thread) o).getId()); } })); mAdapter.notifyDataSetChanged(); } } public void fetch(int page) { model.setFetchingAndParsing(true); fetchPageAt(page); } abstract void fetchPageAt(int page); protected void setRefreshSpinner(boolean visible) { Logger.i("visible %b, enable refresh %b, is fetching %b", visible, mEnablePullToRefresh, model.isFetchingAndParsing()); if (visible) { // Hack. http://stackoverflow.com/questions/26858692/swiperefreshlayout-setrefreshing-not-showing-indicator-initially mSwipe.postDelayed(new Runnable() { @Override public void run() { Logger.i("is fetching %b", model.isFetchingAndParsing()); mSwipe.setRefreshing(true); } }, 100); } else { mSwipe.setRefreshing(false); } } protected abstract String keyOfThreadsToCache(); @Override public void toolbarClick() { listView.setSelection(0); } interface OnScrollUpOrDown { void onUp(int ms); void onDown(int ms); } class DirectionDetectScrollListener extends EndlessScrollListener { private int mLastFirstVisibleItem = -1; private int mState = SCROLL_STATE_IDLE; @Override public void onLoadMore(int page, int totalItemsCount) { if (mThreads.getMeta().hasNextPage() && totalItemsCount > 1 /* list header */) { mActivity.showToast("载入下一页"); setRefreshSpinner(true); fetch(page); } } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { if (slidrInterface != null) { if (scrollState == SCROLL_STATE_IDLE) { slidrInterface.unlock(); } else { slidrInterface.lock(); } } mState = scrollState; } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { super.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount); if (mState == SCROLL_STATE_IDLE) return; if (mLastFirstVisibleItem != -1 && mOnScrollUpOrDown != null) { if (mLastFirstVisibleItem < firstVisibleItem && firstVisibleItem > 3) { mOnScrollUpOrDown.onDown(300); } if (mLastFirstVisibleItem > firstVisibleItem) { mOnScrollUpOrDown.onUp(300); } } mLastFirstVisibleItem = firstVisibleItem; } } protected class Model { public boolean isFetchingAndParsing() { return isFetchingAndParsing; } public void setFetchingAndParsing(boolean fetchingAndParsing) { isFetchingAndParsing = fetchingAndParsing; if (fetchingAndParsing) { setRefreshSpinner(true); } else { setRefreshSpinner(false); } } private boolean isFetchingAndParsing; } public static class EventRefresh {}; }