package com.heinrichreimersoftware.singleinputform;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.CardView;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.inputmethod.InputMethodManager;
import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.ScrollView;
import android.widget.TextSwitcher;
import android.widget.TextView;
import android.widget.ViewAnimator;
import android.widget.ViewSwitcher;
import com.heinrichreimersoftware.singleinputform.steps.Step;
import com.nineoldandroids.animation.ObjectAnimator;
import com.nineoldandroids.util.Property;
import java.util.ArrayList;
import java.util.List;
public abstract class SingleInputFormActivity extends AppCompatActivity {
private static final String KEY_DATA = "key_data";
private static final String KEY_STEP_INDEX = "key_step_index";
private Property<ProgressBar, Integer> PB_PROGRESS_PROPERTY =
new Property<ProgressBar, Integer>(Integer.class, "PB_PROGRESS_PROPERTY"){
@Override
public void set(ProgressBar pb, Integer value){
pb.setProgress(value);
setProgressDrawable();
}
@Override
public Integer get(ProgressBar pb){
return pb.getProgress();
}
};
private static List<Step> sSteps = new ArrayList<Step>();
private FragmentActivity activity = this;
private Bundle setupData = new Bundle();
private int mStepIndex = 0;
private boolean mErrored;
private ScrollView mContainerScrollView;
private TextSwitcher mTitleSwitcher;
private TextSwitcher mErrorSwitcher;
private TextSwitcher mDetailsSwitcher;
private CardView mTextField;
private ViewAnimator mInputSwitcher;
private ImageButton mNextButton;
private ProgressBar mProgressbar;
private TextView mStepText;
private View.OnClickListener mOnNextButtonClickListener = new View.OnClickListener(){
@Override
public void onClick(View v){
nextStep();
}
};
private Drawable mButtonNextIcon;
private Drawable mButtonFinishIcon;
private int mTextFieldBackgroundColor = -1;
private int mProgressBackgroundColor = -1;
private int mTitleTextColor = -1;
private int mDetailsTextColor = -1;
private int mErrorTextColor = -1;
@Override
public void onBackPressed(){
if(mStepIndex == 0){
finish();
}
else{
previousStep();
}
}
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_single_input_form);
loadTheme();
sSteps = getSteps(this);
findViews();
if(savedInstanceState != null){
setupData = savedInstanceState.getBundle(KEY_DATA);
mStepIndex = savedInstanceState.getInt(KEY_STEP_INDEX, 0);
}
setupTitle();
setupInput();
setupError();
setupDetails();
mNextButton.setOnClickListener(mOnNextButtonClickListener);
mErrorSwitcher.setText("");
updateStep();
}
@Override
public void onRestoreInstanceState(Bundle savedInstanceState){
super.onSaveInstanceState(savedInstanceState);
if(savedInstanceState != null){
setupData = savedInstanceState.getBundle(KEY_DATA);
mStepIndex = savedInstanceState.getInt(KEY_STEP_INDEX, 0);
}
}
@Override
public void onSaveInstanceState(Bundle outState){
super.onSaveInstanceState(outState);
setupData = getCurrentStep().save(setupData);
outState.putBundle(KEY_DATA, setupData);
outState.putInt(KEY_STEP_INDEX, mStepIndex);
}
@Override
protected void onPause() {
hideSoftInput();
super.onPause();
}
protected abstract List<Step> getSteps(Context context);
private void findViews(){
mContainerScrollView = (ScrollView) findViewById(R.id.container_scroll_view);
mTitleSwitcher = (TextSwitcher) findViewById(R.id.title_switcher);
mErrorSwitcher = (TextSwitcher) findViewById(R.id.error_switcher);
mDetailsSwitcher = (TextSwitcher) findViewById(R.id.details_switcher);
mTextField = (CardView) findViewById(R.id.text_field);
mInputSwitcher = (ViewAnimator) findViewById(R.id.input_switcher);
mNextButton = (ImageButton) findViewById(R.id.next_button);
mProgressbar = (ProgressBar) findViewById(R.id.progressbar);
mStepText = (TextView) findViewById(R.id.step_text);
}
protected Step getCurrentStep(){
return getStep(mStepIndex);
}
protected Step getStep(int position){
Step step = sSteps.get(position);
step.setContext(this);
return step;
}
private void loadTheme(){
/* Default values */
mButtonNextIcon = getResources().getDrawable(R.drawable.ic_action_next_item);
mButtonFinishIcon = getResources().getDrawable(R.drawable.ic_action_accept);
/* Custom values */
int[] attrs = {R.attr.colorPrimary, R.attr.colorPrimaryDark, android.R.attr.textColorPrimary, android.R.attr.textColorSecondary, R.attr.sifNextIcon, R.attr.sifFinishIcon};
TypedArray array = obtainStyledAttributes(attrs);
mTextFieldBackgroundColor = array.getColor(0, 0);
mProgressBackgroundColor = array.getColor(1, 0);
mTitleTextColor = mErrorTextColor = array.getColor(2, 0);
mDetailsTextColor = array.getColor(3, 0);
Drawable buttonNextIcon = array.getDrawable(4);
if(buttonNextIcon != null)
{
mButtonNextIcon = buttonNextIcon;
}
Drawable buttonFinishIcon = array.getDrawable(5);
if(buttonFinishIcon != null){
mButtonFinishIcon = buttonFinishIcon;
}
array.recycle();
}
private Animation getAnimation(int animationResId, boolean isInAnimation){
final Interpolator interpolator;
if(isInAnimation){
interpolator = new DecelerateInterpolator(1.0f);
}
else{
interpolator = new AccelerateInterpolator(1.0f);
}
Animation animation = AnimationUtils.loadAnimation(activity, animationResId);
animation.setInterpolator(interpolator);
return animation;
}
private void setupTitle(){
mTitleSwitcher.setInAnimation(getAnimation(R.anim.slide_in_to_bottom, true));
mTitleSwitcher.setOutAnimation(getAnimation(R.anim.slide_out_to_top, false));
mTitleSwitcher.setFactory(new ViewSwitcher.ViewFactory(){
@Override
public View makeView(){
TextView view = (TextView) activity.getLayoutInflater().inflate(R.layout.view_title, null);
if(view != null){
view.setTextColor(mTitleTextColor);
}
return view;
}
});
mTitleSwitcher.setText("");
}
private void setupInput(){
mInputSwitcher.setInAnimation(getAnimation(R.anim.alpha_in, true));
mInputSwitcher.setOutAnimation(getAnimation(R.anim.alpha_out, false));
mInputSwitcher.removeAllViews();
for(int i = 0; i < stepsSize(); i++){
mInputSwitcher.addView(getStep(i).getView());
}
}
private void setupError(){
mErrorSwitcher.setInAnimation(getAnimation(android.R.anim.slide_in_left, true));
mErrorSwitcher.setOutAnimation(getAnimation(android.R.anim.slide_out_right, false));
mErrorSwitcher.setFactory(new ViewSwitcher.ViewFactory(){
@Override
public View makeView(){
TextView view = (TextView) activity.getLayoutInflater().inflate(R.layout.view_error, null);
if(view != null && mErrorTextColor != -1){
view.setTextColor(mErrorTextColor);
}
return view;
}
});
mErrorSwitcher.setText("");
}
private void setupDetails(){
mDetailsSwitcher.setInAnimation(getAnimation(R.anim.alpha_in, true));
mDetailsSwitcher.setOutAnimation(getAnimation(R.anim.alpha_out, false));
mDetailsSwitcher.setFactory(new ViewSwitcher.ViewFactory(){
@Override
public View makeView(){
TextView view = (TextView) activity.getLayoutInflater().inflate(R.layout.view_details, null);
if(view != null && mDetailsTextColor != -1){
view.setTextColor(mDetailsTextColor);
}
return view;
}
});
mDetailsSwitcher.setText("");
}
private void updateStep(){
if(mStepIndex >= stepsSize()){
hideSoftInput();
onFormFinished(setupData);
finish();
return;
}
updateViews();
mContainerScrollView.smoothScrollTo(0, 0);
}
private int stepsSize(){
return sSteps.size();
}
private void hideSoftInput(){
InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
View v = getCurrentFocus();
if(v == null) return;
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
protected abstract void onFormFinished(Bundle data);
private void updateViews(){
Step step = getCurrentStep();
if(mStepIndex + 1 >= stepsSize()){
mNextButton.setImageDrawable(mButtonFinishIcon);
step.updateView(true);
}
else{
mNextButton.setImageDrawable(mButtonNextIcon);
step.updateView(false);
}
step.restore(setupData);
setTextFieldBackgroundDrawable();
mInputSwitcher.setDisplayedChild(mStepIndex);
mErrorSwitcher.setText("");
mDetailsSwitcher.setText(step.getDetails());
mTitleSwitcher.setText(step.getTitle());
mStepText.setText(getString(R.string.page_number, mStepIndex + 1, stepsSize()));
mStepText.setTextColor(mDetailsTextColor);
updateProgressbar();
}
private void setTextFieldBackgroundDrawable(){
if(mTextFieldBackgroundColor != -1) {
mTextField.setCardBackgroundColor(mTextFieldBackgroundColor);
}
}
private void setProgressDrawable(){
if(mProgressBackgroundColor != -1) {
Drawable progressDrawable = mProgressbar.getProgressDrawable();
if (progressDrawable != null) {
progressDrawable.setColorFilter(mProgressBackgroundColor, PorterDuff.Mode.SRC_IN);
}
}
}
private void updateProgressbar(){
mProgressbar.setMax(stepsSize() * 100);
ObjectAnimator.ofInt(mProgressbar, PB_PROGRESS_PROPERTY, mStepIndex * 100).start();
}
protected void previousStep(){
setupData = getCurrentStep().save(setupData);
mStepIndex--;
updateStep();
}
protected void nextStep(){
Step step = getCurrentStep();
boolean checkStep = checkStep();
if(!checkStep){
if(!mErrored){
mErrored = true;
mErrorSwitcher.setText(step.getError());
}
}
else{
mErrored = false;
}
if(mErrored){
return;
}
setupData = step.save(setupData);
mStepIndex++;
updateStep();
}
private boolean checkStep(){
return getCurrentStep().check();
}
}