/* * Copyright (C) 2013 Simon Vig Therkildsen * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.simonvt.cathode.ui.fragment; import android.content.Context; import android.os.Bundle; import android.support.annotation.Nullable; import android.view.View; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.widget.AbsListView; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.TextView; import butterknife.BindView; import net.simonvt.cathode.R; public abstract class AbsAdapterFragment extends BaseFragment { private static final String SAVED_EMPTY_TEXT = "savedEmptyText"; private static final int STATE_NONE = -1; private static final int STATE_PROGRESS_VISIBLE = 0; private static final int STATE_LIST_VISIBLE = 1; private static final int ANIMATION_DURATION = 600; private BaseAdapter adapter; @BindView(R.id.progressContainer) @Nullable View progressContainer; @BindView(R.id.listContainer) @Nullable View listContainer; @BindView(android.R.id.list) AbsListView adapterView; @BindView(android.R.id.empty) TextView empty; private Context appContext; private String emptyText; protected boolean attachLongClickListener; private boolean animating; private int currentState = STATE_PROGRESS_VISIBLE; private int pendingStateChange = STATE_NONE; @Override public void onCreate(Bundle inState) { super.onCreate(inState); appContext = getActivity().getApplicationContext(); if (inState != null) { emptyText = inState.getString(SAVED_EMPTY_TEXT); } } @Override public void onSaveInstanceState(Bundle outState) { outState.putString(SAVED_EMPTY_TEXT, emptyText); super.onSaveInstanceState(outState); } @Override public void onViewCreated(View view, Bundle inState) { super.onViewCreated(view, inState); if (emptyText != null) empty.setText(emptyText); adapterView.setOnItemClickListener(onClickListener); if (attachLongClickListener) adapterView.setOnItemLongClickListener(onLongClickListener); adapterView.setEmptyView(empty); if (adapter != null) adapterView.setAdapter(adapter); if (listContainer != null && progressContainer != null) { view.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { @Override public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { v.removeOnLayoutChangeListener(this); if (adapter == null) { listContainer.setVisibility(View.GONE); progressContainer.setVisibility(View.VISIBLE); currentState = STATE_PROGRESS_VISIBLE; } else { currentState = STATE_LIST_VISIBLE; listContainer.setVisibility(View.VISIBLE); progressContainer.setVisibility(View.GONE); } } }); } else if (listContainer != null || progressContainer != null) { throw new IllegalStateException( "Layout must contain both listContainer and progressContainer if one exists"); } } @Override public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) { Animation animation = null; if (nextAnim != 0) { animation = AnimationUtils.loadAnimation(getActivity(), nextAnim); animation.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { animating = true; } @Override public void onAnimationEnd(Animation animation) { animating = false; if (pendingStateChange != STATE_NONE) { changeState(pendingStateChange, true); pendingStateChange = STATE_NONE; } } @Override public void onAnimationRepeat(Animation animation) { } }); } return animation; } private void changeState(final int newState, final boolean animate) { if (newState == currentState) { return; } if (listContainer == null || progressContainer == null) { return; } if (animating) { pendingStateChange = newState; return; } currentState = newState; if (newState == STATE_PROGRESS_VISIBLE && listContainer.getVisibility() != View.VISIBLE) { return; } if (newState == STATE_LIST_VISIBLE && !animate) { listContainer.setVisibility(View.VISIBLE); progressContainer.setVisibility(View.GONE); } else if (newState == STATE_PROGRESS_VISIBLE && !animate) { listContainer.setVisibility(View.GONE); progressContainer.setVisibility(View.VISIBLE); } else { listContainer.setVisibility(View.VISIBLE); progressContainer.setVisibility(View.VISIBLE); final Runnable onAnimationEnd = new Runnable() { @Override public void run() { if (progressContainer == null) { // In case fragment is removed before animation is done return; } if (newState == STATE_LIST_VISIBLE) { progressContainer.setVisibility(View.GONE); } else { listContainer.setVisibility(View.GONE); if (adapter == null) { adapterView.setAdapter(null); } } progressContainer.setAlpha(1.0f); listContainer.setAlpha(1.0f); } }; if (newState == STATE_LIST_VISIBLE) { listContainer.animate().alpha(1.0f).withEndAction(onAnimationEnd); progressContainer.animate().alpha(0.0f); } else { listContainer.animate().alpha(0.0f).withEndAction(onAnimationEnd); progressContainer.animate().alpha(1.0f); } } } private final AdapterView.OnItemClickListener onClickListener = new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View v, int position, long id) { AbsAdapterFragment.this.onItemClick(parent, v, position, id); } }; protected void onItemClick(AdapterView l, View v, int position, long id) { } private final AdapterView.OnItemLongClickListener onLongClickListener = new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> adapterView, View v, int position, long id) { return AbsAdapterFragment.this.onItemLongClick(adapterView, v, position, id); } }; protected boolean onItemLongClick(AdapterView l, View v, int position, long id) { return false; } public AbsListView getAdapterView() { return adapterView; } public void setAdapter(BaseAdapter adapter) { if (adapter != this.adapter) { this.adapter = adapter; if (this.adapter != null) { if (adapterView != null) { adapterView.setAdapter(this.adapter); if (listContainer != null && listContainer.getVisibility() != View.VISIBLE) { changeState(STATE_LIST_VISIBLE, true); } } } else if (adapterView != null) { changeState(STATE_PROGRESS_VISIBLE, true); } } } public BaseAdapter getAdapter() { return adapter; } public void clearEmptyText() { emptyText = ""; if (empty != null) { empty.setText(emptyText); } } final void setEmptyText(String text) { if (text == null) { text = ""; } emptyText = text; if (empty != null) { empty.setText(emptyText); } } final void setEmptyText(int resId) { String text = appContext.getString(resId); if (text != null) { emptyText = text; if (empty != null) { empty.setText(emptyText); } } } final void setEmptyText(int resId, Object... formatArgs) { String text = appContext.getString(resId, formatArgs); if (text != null) { emptyText = text; if (empty != null) { empty.setText(emptyText); } } } }