package org.softeg.slartus.forpdaplus.listfragments;/* * Created by slinkin on 10.04.2014. */ import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.support.v4.widget.SwipeRefreshLayout; import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; import android.widget.BaseExpandableListAdapter; import android.widget.ExpandableListAdapter; import android.widget.ExpandableListView; import android.widget.Filterable; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import org.softeg.slartus.forpdaapi.IListItem; import org.softeg.slartus.forpdaplus.App; import org.softeg.slartus.forpdaplus.Client; import org.softeg.slartus.forpdaplus.R; import org.softeg.slartus.forpdaplus.common.AppLog; import org.softeg.slartus.forpdaplus.db.CacheDbHelper; import org.softeg.slartus.forpdaplus.listfragments.adapters.ExpandableMyListAdapter; import org.softeg.slartus.forpdaplus.prefs.Preferences; import org.softeg.sqliteannotations.BaseDao; import java.io.IOException; import java.util.ArrayList; public abstract class BaseExpandableListFragment extends BaseBrickFragment implements ExpandableListView.OnChildClickListener { protected ArrayList<ExpandableGroup> mData = new ArrayList<>(); protected ArrayList<ExpandableGroup> mLoadResultList; protected ArrayList<ExpandableGroup> mCacheList = new ArrayList<>(); private static final String TAG = "BaseExpandableListFragment"; public static final String FIRST_VISIBLE_ROW_KEY = "FIRST_VISIBLE_ROW_KEY"; public static final String TOP_KEY = "TOP_KEY"; protected Handler mHandler = new Handler(); private int m_FirstVisibleRow = 0; private int m_Top = 0; protected void createMenu() { } public BaseExpandableListFragment() { super(); } protected Bundle args; @Override public boolean dispatchKeyEvent(KeyEvent event) { if (!Preferences.Lists.getScrollByButtons()) return false; int action = event.getAction(); ListView scrollView = getListView(); int visibleItemsCount = scrollView.getLastVisiblePosition() - scrollView.getFirstVisiblePosition(); int keyCode = event.getKeyCode(); if(Preferences.System.isScrollUpButton(keyCode)){ if (action == KeyEvent.ACTION_DOWN) scrollView.setSelection(Math.max(scrollView.getFirstVisiblePosition() - visibleItemsCount, 0)); return true;// true надо обязательно возвращать даже если не ACTION_DOWN иначе звук нажатия } if(Preferences.System.isScrollDownButton(keyCode)){ if (action == KeyEvent.ACTION_DOWN) scrollView.setSelection(Math.min(scrollView.getLastVisiblePosition(), scrollView.getCount() - 1)); return true;// true надо обязательно возвращать даже если не ACTION_DOWN иначе звук нажатия } return false; } @Override public void onCreate(android.os.Bundle savedInstanceState) { super.onCreate(savedInstanceState); createMenu(); if (getArguments() != null) { args = getArguments(); } if (savedInstanceState != null) { args = savedInstanceState; } if (savedInstanceState != null) { m_FirstVisibleRow = savedInstanceState.getInt(FIRST_VISIBLE_ROW_KEY, m_FirstVisibleRow); m_Top = savedInstanceState.getInt(TOP_KEY, m_Top); } } private ExpandableListView mListView; private TextView mEmptyTextView; protected int getViewId() { return R.layout.expandable_list_fragment; } @Override public android.view.View onCreateView(android.view.LayoutInflater inflater, android.view.ViewGroup container, android.os.Bundle savedInstanceState) { view = inflater.inflate(getViewId(), container, false); assert view != null; mListView = (ExpandableListView) findViewById(android.R.id.list); mListView.setOnChildClickListener(this); mEmptyTextView = (TextView) findViewById(android.R.id.empty); mListView.setEmptyView(mEmptyTextView); return view; } @Override public void onSaveInstanceState(android.os.Bundle outState) { if (args != null) outState.putAll(args); outState.putInt(FIRST_VISIBLE_ROW_KEY, m_FirstVisibleRow); outState.putInt(TOP_KEY, m_Top); super.onSaveInstanceState(outState); } protected BaseExpandableListAdapter mAdapter; public Context getContext() { return getActivity(); } protected SwipeRefreshLayout mSwipeRefreshLayout; protected void saveListViewScrollPosition() { m_FirstVisibleRow = getListView().getFirstVisiblePosition(); View v = getListView().getChildAt(0); m_Top = (v == null) ? 0 : v.getTop(); } protected void restoreListViewScrollPosition() { getListView().setSelectionFromTop(m_FirstVisibleRow, m_Top); } protected ExpandableListView getListView() { return mListView; } @Override public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) { return false; } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); mSwipeRefreshLayout = createSwipeRefreshLayout(view); } protected SwipeRefreshLayout createSwipeRefreshLayout(View view) { // This is the View which is created by ListFragment ViewGroup viewGroup = (ViewGroup) view; SwipeRefreshLayout swipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.ptr_layout); swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { loadData(true); } }); swipeRefreshLayout.setColorSchemeResources(App.getInstance().getMainAccentColor()); swipeRefreshLayout.setProgressBackgroundColorSchemeResource(App.getInstance().getSwipeRefreshBackground()); return swipeRefreshLayout; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); registerForContextMenu(getListView()); setListShown(false); mAdapter = createAdapter(); setListAdapter(mAdapter); mCacheTask = new LoadCacheTask(); mCacheTask.execute(); } private void setListAdapter(ExpandableListAdapter mAdapter) { getListView().setAdapter(mAdapter); } protected void setListShown(boolean b) { //mListView.setVisibility(b?); } public ExpandableListAdapter getAdapter() { return mAdapter; } protected BaseExpandableListAdapter createAdapter() { return new ExpandableMyListAdapter(getActivity(), mData); } protected void setLoading(final Boolean loading) { try { if (getActivity() == null) return; //mSwipeRefreshLayout.setRefreshing(loading); mSwipeRefreshLayout.post(new Runnable() { @Override public void run() { mSwipeRefreshLayout.setRefreshing(loading); } }); if (loading) { setEmptyText(App.getContext().getString(R.string.loading)); } else { setEmptyText(App.getContext().getString(R.string.no_data)); } } catch (Throwable ignore) { android.util.Log.e("TAG", ignore.toString()); } } protected void setEmptyText(String s) { mEmptyTextView.setText(s); } public void filter(CharSequence text) { if (getAdapter() instanceof Filterable) { ((Filterable) getAdapter()).getFilter().filter(text); } } public void loadCache() throws IOException, IllegalAccessException, NoSuchFieldException, java.lang.InstantiationException { } public void saveCache() throws Exception { } protected <T> void updateItemCache(final T item, final Class<T> tClass, Boolean newThread) { if (newThread) { new Thread(new Runnable() { @Override public void run() { updateItemCache(item, tClass); } }).start(); } else { updateItemCache(item, tClass); } } private <T> void updateItemCache(T item, Class<T> tClass) { try { CacheDbHelper cacheDbHelper = new CacheDbHelper(App.getContext()); SQLiteDatabase db = null; try { db = cacheDbHelper.getWritableDatabase(); BaseDao<T> baseDao = new BaseDao<>(App.getContext(), db, getListName(), tClass); baseDao.update(item, ((IListItem) item).getId().toString()); } finally { if (db != null) db.close(); } } catch (Throwable ex) { // Log.e(getContext(), ex); } } public void trySaveCache() { try { saveCache(); } catch (Throwable e) { AppLog.eToast(getContext(), e); } } @Override public void onDestroy() { super.onDestroy(); if (mCacheTask != null) mCacheTask.cancel(false); if (mTask != null) mTask.cancel(null); } private Task mTask = null; private LoadCacheTask mCacheTask = null; public void startLoad() { if (mTask != null) return; loadData(true); } protected Task createTask(Boolean isRefresh) { return new Task(isRefresh); } public void loadData(final boolean isRefresh) { saveListViewScrollPosition(); Runnable runnable = new Runnable() { @Override public void run() { if (needLogin()) { Client.getInstance().checkLoginByCookies(); if (!Client.getInstance().getLogined()) Client.getInstance().showLoginForm(getContext(), new Client.OnUserChangedListener() { public void onUserChanged(String user, Boolean success) { loadData(isRefresh); } }); } mTask = createTask(isRefresh); mTask.execute(); } }; if (mTask != null && mTask.getStatus() != AsyncTask.Status.FINISHED) mTask.cancel(runnable); else { runnable.run(); } } protected abstract boolean inBackground(boolean isRefresh) throws Throwable; protected abstract void deliveryResult(boolean isRefresh); private void beforeDeliveryResult() { saveListViewScrollPosition(); } private void afterDeliveryResult() { setListShown(true); mAdapter.notifyDataSetChanged(); setEmptyText(App.getContext().getString(R.string.no_data)); new Thread(new Runnable() { @Override public void run() { trySaveCache(); } }).start(); restoreListViewScrollPosition(); } protected void onFailureResult() { } protected Boolean isCancelled() { return mTask.isCancelled(); } public class Task extends AsyncTask<Boolean, Void, Boolean> { protected Boolean mRefresh; private Runnable onCancelAction; protected Throwable mEx; public Task(Boolean refresh) { mRefresh = refresh; } @Override protected void onPreExecute() { super.onPreExecute(); setLoading(true); } public void cancel(Runnable runnable) { onCancelAction = runnable; cancel(false); } @Override protected Boolean doInBackground(Boolean[] p1) { try { return inBackground(mRefresh); } catch (Throwable e) { mEx = e; } return false; } @Override protected void onPostExecute(Boolean result) { super.onPostExecute(result); if (result && !isCancelled()) { beforeDeliveryResult(); deliveryResult(mRefresh); afterDeliveryResult(); } if (!isCancelled()) setLoading(false); if (mEx != null) AppLog.e(getActivity(), mEx, new Runnable() { @Override public void run() { loadData(mRefresh); } }); else if (!result) { onFailureResult(); } } @Override protected void onCancelled(Boolean result) { if (onCancelAction != null) onCancelAction.run(); } @Override protected void onCancelled() { if (onCancelAction != null) onCancelAction.run(); } } public class LoadCacheTask extends AsyncTask<Boolean, Void, Boolean> { private Throwable mEx; @Override protected void onPreExecute() { super.onPreExecute(); setLoading(true); } public void cancel() { cancel(false); } @Override protected Boolean doInBackground(Boolean[] p1) { try { //loadCache(); return true; } catch (Throwable e) { mEx = e; } return false; } @Override protected void onPostExecute(Boolean result) { super.onPostExecute(result); if (mEx != null) Toast.makeText(getContext(), AppLog.getLocalizedMessage(mEx, App.getContext().getString(R.string.cache_load_error)), Toast.LENGTH_SHORT).show(); if (!isCancelled()) { deliveryCache(); restoreListViewScrollPosition(); startLoad(); } } @Override protected void onCancelled(Boolean result) { setLoading(false); } @Override protected void onCancelled() { setLoading(false); } } protected void deliveryCache() { mData.clear(); if (mCacheList != null) { mData.addAll(mCacheList); mCacheList.clear(); } mAdapter.notifyDataSetChanged(); } public class ExpandableGroup { private String mName; private String mTitle; private ArrayList<IListItem> mData = new ArrayList<>(); public ExpandableGroup(String name, String title) { mName = name; mTitle = title; } public ArrayList<IListItem> getChildren() { return mData; } public String getTitle() { return mTitle; } } }