/*
* Copyright 2012 Roman Nurik
* Copyright 2013 Hari Krishna Dulipudi
*
* 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 dev.dworks.libs.awizard;
import java.util.List;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.ActionBarActivity;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import dev.dworks.libs.awizard.model.PageFragmentCallbacks;
import dev.dworks.libs.awizard.model.ReviewCallbacks;
import dev.dworks.libs.awizard.model.WizardModel;
import dev.dworks.libs.awizard.model.WizardModelCallbacks;
import dev.dworks.libs.awizard.model.page.DonePage;
import dev.dworks.libs.awizard.model.page.Page;
import dev.dworks.libs.awizard.model.page.ReviewPage;
import dev.dworks.libs.awizard.model.ui.StepPagerStrip;
/**
* @author HaKr
*
*/
public class WizardActivity extends ActionBarActivity implements
PageFragmentCallbacks,
ReviewCallbacks,
WizardModelCallbacks {
public static final int HORIZONTAL = 0;
public static final int VERTICAL = 1;
//The view pager for the wizard
private ViewPager mPager;
//FragmentStatePagerAdapter adapter for the wizard
private PagerAdapter mPagerAdapter;
//Set to true to edit data at review
private boolean mEditingAfterReview;
private String mReviewText = null;
private String mDoneText = null;
//The wizard model for the wizard
protected WizardModel mWizardModel;
private boolean mConsumePageSelectedEvent;
//Next button in the wizard
private Button mNextButton;
//Previous button in the wizard
private Button mPrevButton;
private List<Page> mCurrentPageSequence;
private StepPagerStrip mStepPagerStrip;
private int mReviewPagePosition;
private int mDonePagePosition;
private int mOrientation = HORIZONTAL;
private boolean mDataChanged = false;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_wizard);
if (savedInstanceState != null) {
mWizardModel.load(savedInstanceState.getBundle("model"));
mDataChanged = savedInstanceState.getBoolean("dataChanged");
}
}
private void ensureControls() {
mPagerAdapter = new PagerAdapter(getSupportFragmentManager());
mPager = (ViewPager) findViewById(R.id.pager);
if (mPager == null) {
throw new RuntimeException(
"Your content must have a android.support.v4.view.ViewPager whose id attribute is " +
"'R.id.pager'");
}
//mPager.setOrientation(mOrientation);
mPager.setAdapter(mPagerAdapter);
mPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
mStepPagerStrip.setCurrentPage(position);
if (mConsumePageSelectedEvent) {
mConsumePageSelectedEvent = false;
return;
}
mEditingAfterReview = false;
updateBottomBar();
}
});
mStepPagerStrip = (StepPagerStrip) findViewById(R.id.strip);
mStepPagerStrip.setOrientation(mOrientation);
mStepPagerStrip.setOnPageSelectedListener(new StepPagerStrip.OnPageSelectedListener() {
@Override
public void onPageStripSelected(int position) {
position = Math.min(mPagerAdapter.getCount() - 1, position);
if (mPager.getCurrentItem() != position) {
mPager.setCurrentItem(position);
}
}
});
mNextButton = (Button) findViewById(R.id.next_button);
mNextButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mPager.getCurrentItem() == mCurrentPageSequence.size() - 1) {
onDoneClick();
} else {
if (mEditingAfterReview) {
mPager.setCurrentItem(mReviewPagePosition);
} else {
if(mPager.getCurrentItem() == mReviewPagePosition){
Page page = mCurrentPageSequence.get(mReviewPagePosition);
page.getData().putBoolean(ReviewPage.PROCESS_DATA_KEY, true);
page.notifyDataChanged();
}
mPager.setCurrentItem(mPager.getCurrentItem() + 1);
}
}
}
});
mPrevButton = (Button) findViewById(R.id.prev_button);
mPrevButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mPager.setCurrentItem(mPager.getCurrentItem() - 1);
}
});
mDonePagePosition = getDonePagePosition();
mReviewPagePosition = getReviewPagePosition();
mStepPagerStrip.setReviewPagePosition(mReviewPagePosition);
mStepPagerStrip.setDonePagePosition(mDonePagePosition);
}
public final void setReviewText(String finish) {
this.mReviewText = finish;
}
public final void setDoneText(String finish) {
this.mDoneText = finish;
}
/**
* on Review next action
*/
public void onConfirmClick() {
finish();
}
/**
* on Done next action
*/
public void onDoneClick() {
finish();
}
@Override
public final void onPageTreeChanged() {
mCurrentPageSequence = mWizardModel.getCurrentPageSequence();
updatePagerStrip();
mPagerAdapter.notifyDataSetChanged();
updateBottomBar();
}
private void updatePagerStrip() {
int pageCount = mCurrentPageSequence.size();
recalculateCutOffPage();
mStepPagerStrip.setPageCount(pageCount);
mReviewPagePosition = getReviewPagePosition();
mDonePagePosition = getDonePagePosition();
mStepPagerStrip.setReviewPagePosition(mReviewPagePosition);
mStepPagerStrip.setDonePagePosition(mDonePagePosition);
}
private void updateBottomBar() {
if(null == mNextButton || null == mPrevButton){
return;
}
TypedValue v = new TypedValue();
getTheme().resolveAttribute(android.R.attr.textAppearanceMedium, v, true);
int position = mPager.getCurrentItem();
if (position == mReviewPagePosition) {
mReviewText = mReviewText != null ? mReviewText : getResources().getString(R.string.review_next);
mNextButton.setText(mReviewText);
mNextButton.setBackgroundResource(R.drawable.review_backgrounds);
mNextButton.setTextAppearance(this, R.style.TextAppearanceFinish);
}else if (position == mDonePagePosition) {
mDoneText = mDoneText != null ? mDoneText : getResources().getString(R.string.done_next);
mNextButton.setText(mDoneText);
mNextButton.setBackgroundResource(R.drawable.done_backgrounds);
mNextButton.setTextAppearance(this, R.style.TextAppearanceFinish);
}else if (position == mCurrentPageSequence.size() - 1) {
mNextButton.setText(R.string.done_next);
if(mDonePagePosition != -1){
mNextButton.setBackgroundResource(R.drawable.selectable_item_background);
mNextButton.setTextAppearance(this, v.resourceId);
}
else{
mNextButton.setBackgroundResource(R.drawable.done_backgrounds);
mNextButton.setTextAppearance(this, R.style.TextAppearanceFinish);
}
}else {
mNextButton.setText(mEditingAfterReview ? R.string.review : R.string.next);
mNextButton.setBackgroundResource(R.drawable.selectable_item_background);
mNextButton.setTextAppearance(this, v.resourceId);
mPrevButton.setTextAppearance(this, v.resourceId);
mNextButton.setEnabled(position != mPagerAdapter.getCutOffPage());
}
mPrevButton.setVisibility(position <= 0 ? View.INVISIBLE : View.VISIBLE);
}
@Override
protected void onDestroy() {
super.onDestroy();
mWizardModel.unregisterListener(this);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBundle("model", mWizardModel.save());
outState.putBoolean("dataChanged", mDataChanged);
}
@Override
public final WizardModel getWizardModel() {
return mWizardModel;
}
public final void setWizardModel(WizardModel wizardModel) {
mWizardModel = wizardModel;
if (mWizardModel == null) {
throw new RuntimeException("Wizard Model cannot be empty");
}
mWizardModel.registerListener(this);
//TODO: Change in support lib causing null pointer
mCurrentPageSequence = mWizardModel.getCurrentPageSequence();
ensureControls();
onPageTreeChanged();
}
public int getOrientation() {
return mOrientation;
}
public void setOrientation(int orientation) {
switch (orientation) {
case HORIZONTAL:
case VERTICAL:
break;
default:
throw new IllegalArgumentException("Only HORIZONTAL and VERTICAL are valid orientations.");
}
mOrientation = orientation;
if(null != mStepPagerStrip){
mStepPagerStrip.setOrientation(mOrientation);
}
}
@Override
public final void onEditScreenAfterReview(String key) {
for (int i = mCurrentPageSequence.size() - 1; i >= 0; i--) {
if (mCurrentPageSequence.get(i).getKey().equals(key)) {
mConsumePageSelectedEvent = true;
mEditingAfterReview = true;
mPager.setCurrentItem(i);
updateBottomBar();
break;
}
}
}
@Override
public final void onPageDataChanged(Page page) {
mDataChanged = true;
if (page.isRequired()) {
if (recalculateCutOffPage()) {
mPagerAdapter.notifyDataSetChanged();
updateBottomBar();
}
}
}
@Override
public Page onGetPage(String key) {
return mWizardModel.findByKey(key);
}
public boolean getDataChanged() {
return mDataChanged;
}
private final int getReviewPagePosition() {
int pagePosition = -1;
for (int i = 0; i < mCurrentPageSequence.size(); i++) {
Page page = mCurrentPageSequence.get(i);
if (page instanceof ReviewPage) {
pagePosition = i;
break;
}
}
return pagePosition;
}
private final int getDonePagePosition() {
int pagePosition = -1;
for (int i = 0; i < mCurrentPageSequence.size(); i++) {
Page page = mCurrentPageSequence.get(i);
if (page instanceof DonePage) {
pagePosition = i;
break;
}
}
return pagePosition;
}
private final boolean recalculateCutOffPage() {
// Cut off the pager adapter at first required page that isn't completed
int cutOffPage = mCurrentPageSequence.size() + 1;
for (int i = 0; i < mCurrentPageSequence.size(); i++) {
Page page = mCurrentPageSequence.get(i);
if (page.isRequired() && !page.isCompleted()) {
cutOffPage = i;
break;
}
}
if (mPagerAdapter.getCutOffPage() != cutOffPage) {
mPagerAdapter.setCutOffPage(cutOffPage);
return true;
}
return false;
}
/*
* Adapter for fragments
* */
private class PagerAdapter extends FragmentStatePagerAdapter {
private int mCutOffPage;
private Fragment mPrimaryItem;
public PagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int i) {
/* if (i >= mCurrentPageSequence.size()) {
return new ReviewFragment();
}
*/
return mCurrentPageSequence.get(i).createFragment();
}
@Override
public int getItemPosition(Object object) {
// TODO: be smarter about this
if (object == mPrimaryItem) {
// Re-use the current fragment (its position never changes)
return POSITION_UNCHANGED;
}
return POSITION_NONE;
}
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
super.setPrimaryItem(container, position, object);
mPrimaryItem = (Fragment) object;
}
@Override
public int getCount() {
if (mCurrentPageSequence == null) {
return 0;
}
return Math.min(mCutOffPage + 1, mCurrentPageSequence.size() /* + 1 */);
}
public void setCutOffPage(int cutOffPage) {
if (cutOffPage < 0) {
cutOffPage = Integer.MAX_VALUE;
}
mCutOffPage = cutOffPage;
}
public int getCutOffPage() {
return mCutOffPage;
}
}
}