Skip to content

Commit

Permalink
Stepper feedback + sample app main screen redesign (#91)
Browse files Browse the repository at this point in the history
- Added stepper feedback
- added GIFs for the stepper feedback and tab error animations
- redesigned the home screen of the sample app
  • Loading branch information
zawadz88 authored Mar 17, 2017
1 parent 11be3bf commit 48d8473
Show file tree
Hide file tree
Showing 44 changed files with 1,211 additions and 288 deletions.
103 changes: 79 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Quoting the [documentation](https://www.google.com/design/spec/components/steppe
## Download (from JCenter)
```groovy
compile 'com.stepstone.stepper:material-stepper:3.1.0'
compile 'com.stepstone.stepper:material-stepper:3.2.0'
```

## Supported steppers
Expand All @@ -30,6 +30,8 @@ compile 'com.stepstone.stepper:material-stepper:3.1.0'
- embedding the stepper anywhere in the view hierarchy and changing the stepper type for various device configurations, e.g. phone/tablet, portrait/landscape
- step validation
- use with Fragments or Views
- showing errors in tabs
- showing stepper feedback for ongoing operations (see [Stepper feedback](https://material.io/guidelines/components/steppers.html#steppers-types-of-steppers))

## Getting started

Expand Down Expand Up @@ -341,10 +343,60 @@ For an example of how to use it with views please see the sample app.

### Showing an error on tabs if step verification failed
To show an error in the tabbed stepper if step verification fails you need to set `ms_showErrorStateEnabled` attribute to `true`.
<p><img src ="./gifs/error-on-tabs.gif" width="360" height="640"/></p>
<p><img src ="./gifs/error-on-tabs.gif" width="640" height="360"/></p>

If you want to keep the error displayed when going back to the previous step you need to also set `ms_showErrorStateOnBackEnabled` to `true`.

### Stepper feedback
It is possible to show stepper feedback for ongoing operations (see [Stepper feedback](https://material.io/guidelines/components/steppers.html#steppers-types-of-steppers)).
To do so you firstly need to set ```ms_stepperFeedbackType``` to one or more of:
* ```tabs``` - shows a progress message instead of the tabs during operation,
* ```content``` - shows a progress bar on top of the steps' content and partially fades the content out during operation,
* ```disabled_bottom_navigation``` - disables the buttons in the bottom navigation during operation.
The default is ```none``` which does nothing. It is possible to use multiple flags together.

After setting this to show the feedback you need to call ```StepperLayout#showProgress(@NonNull String progressMessage)```
and do hide the progress indicator you need to call ```StepperLayout#hideProgress()```.

<p><img src ="./gifs/stepper-feedback.gif" width="640" height="360"/></p>

E.g.
In layout:
```xml
<?xml version="1.0" encoding="utf-8"?>
<com.stepstone.stepper.StepperLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/stepperLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:ms_stepperType="tabs"
app:ms_stepperFeedbackType="tabs|content|disabled_bottom_navigation" />
```

and in BlockingStep:

```java
public class StepperFeedbackStepFragment extends Fragment implements BlockingStep {

//...

@Override
@UiThread
public void onNextClicked(final StepperLayout.OnNextClickedCallback callback) {
callback.getStepperLayout().showProgress("Operation in progress, please wait...");
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
callback.goToNextStep();
callback.getStepperLayout().hideProgress();
}
}, 2000L);
}

//...

```

### Custom styling
Basic styling can be done by choosing the active and inactive step colors.
There are some additional properties which can be changed directly from StepperLayout's attributes e.g. the background of bottom navigation buttons (see <a href="#stepperlayout-attributes">StepperLayout attributes</a>)
Expand All @@ -356,28 +408,29 @@ See 'Custom StepperLayout theme' in the sample app for an example.
For other examples, e.g. persisting state on rotation, displaying errors, changing whether the user can go to the next step, etc. check out the sample app.

## StepperLayout attributes
| Attribute name | Format | Description |
| --------------------------------|-------------------------------------------|-------------|
| *ms_stepperType* | one of `dots`, `progress_bar` or `tabs` | **REQUIRED:** Type of the stepper |
| *ms_backButtonColor* | color or reference | BACK button's text color |
| *ms_nextButtonColor* | color or reference | NEXT button's text color |
| *ms_completeButtonColor* | color or reference | COMPLETE button's text color |
| *ms_activeStepColor* | color or reference | Active step's color |
| *ms_inactiveStepColor* | color or reference | Inactive step's color |
| *ms_bottomNavigationBackground* | reference | Background of the bottom navigation |
| *ms_backButtonBackground* | reference | BACK button's background |
| *ms_nextButtonBackground* | reference | NEXT button's background |
| *ms_completeButtonBackground* | reference | COMPLETE button's background |
| *ms_backButtonText* | string or reference | BACK button's text |
| *ms_nextButtonText* | string or reference | NEXT button's text |
| *ms_completeButtonText* | string or reference | COMPLETE button's text |
| *ms_tabStepDividerWidth* | dimension or reference | The width of the horizontal tab divider used in tabs stepper type |
| *ms_showBackButtonOnFirstStep* | boolean | Flag indicating if the Back (Previous step) button should be shown on the first step. False by default. |
| *ms_errorColor* | color or reference | Error color in Tabs stepper |
| *ms_showErrorStateEnabled* | boolean | Flag indicating whether to show the error state. Only applicable for 'tabs' type. False by default. |
| *ms_showErrorStateOnBackEnabled*| boolean | Flag indicating whether to keep showing the error state when user moves back. Only applicable for 'tabs' type. False by default. |
| *ms_tabNavigationEnabled* | boolean | Flag indicating whether step navigation is possible by clicking on the tabs directly. Only applicable for 'tabs' type. True by default. |
| *ms_stepperLayoutTheme* | reference | Theme to use for even more custom styling of the stepper layout. It is recommended that it should extend @style/MSDefaultStepperLayoutTheme, which is the default theme used. |
| Attribute name | Format | Description |
| --------------------------------|---------------------------------------------------------------------|-------------|
| *ms_stepperType* | one of `dots`, `progress_bar` or `tabs` | **REQUIRED:** Type of the stepper |
| *ms_backButtonColor* | color or reference | BACK button's text color |
| *ms_nextButtonColor* | color or reference | NEXT button's text color |
| *ms_completeButtonColor* | color or reference | COMPLETE button's text color |
| *ms_activeStepColor* | color or reference | Active step's color |
| *ms_inactiveStepColor* | color or reference | Inactive step's color |
| *ms_bottomNavigationBackground* | reference | Background of the bottom navigation |
| *ms_backButtonBackground* | reference | BACK button's background |
| *ms_nextButtonBackground* | reference | NEXT button's background |
| *ms_completeButtonBackground* | reference | COMPLETE button's background |
| *ms_backButtonText* | string or reference | BACK button's text |
| *ms_nextButtonText* | string or reference | NEXT button's text |
| *ms_completeButtonText* | string or reference | COMPLETE button's text |
| *ms_tabStepDividerWidth* | dimension or reference | The width of the horizontal tab divider used in tabs stepper type |
| *ms_showBackButtonOnFirstStep* | boolean | Flag indicating if the Back (Previous step) button should be shown on the first step. False by default. |
| *ms_errorColor* | color or reference | Error color in Tabs stepper |
| *ms_showErrorStateEnabled* | boolean | Flag indicating whether to show the error state. Only applicable for 'tabs' type. False by default. |
| *ms_showErrorStateOnBackEnabled*| boolean | Flag indicating whether to keep showing the error state when user moves back. Only applicable for 'tabs' type. False by default. |
| *ms_tabNavigationEnabled* | boolean | Flag indicating whether step navigation is possible by clicking on the tabs directly. Only applicable for 'tabs' type. True by default. |
| *ms_stepperFeedbackType* | flag(s): `none` or `tabs`, `content` & `disabled_bottom_navigation` | Type(s) of stepper feedback. Can be a combination of `tabs`, `content` & `disabled_bottom_navigation`. Default is `none`.|
| *ms_stepperLayoutTheme* | reference | Theme to use for even more custom styling of the stepper layout. It is recommended that it should extend @style/MSDefaultStepperLayoutTheme, which is the default theme used. |
### StepperLayout style attributes
A list of `ms_stepperLayoutTheme` attributes responsible for styling of StepperLayout's child views.
Expand All @@ -390,8 +443,10 @@ A list of `ms_stepperLayoutTheme` attributes responsible for styling of StepperL
| *ms_nextNavigationButtonStyle* | Used by ms_stepNextButton in layout/ms_stepper_layout |
| *ms_completeNavigationButtonStyle*| Used by ms_stepCompleteButton in layout/ms_stepper_layout |
| *ms_colorableProgressBarStyle* | Used by ms_stepProgressBar in layout/ms_stepper_layout |
| *ms_stepPagerProgressBarStyle* | Used by ms_stepPagerProgressBar in layout/ms_stepper_layout |
| *ms_stepTabsScrollViewStyle* | Used by ms_stepTabsScrollView in layout/ms_tabs_container |
| *ms_stepTabsInnerContainerStyle* | Used by ms_stepTabsInnerContainer in layout/ms_tabs_container |
| *ms_stepTabsProgressMessageStyle* | Used by ms_stepTabsProgressMessage in layout/ms_tabs_container|
| *ms_stepTabContainerStyle* | Used in layout/ms_step_tab_container |
| *ms_stepTabNumberStyle* | Used by ms_stepNumber in layout/ms_step_tab |
| *ms_stepTabDoneIndicatorStyle* | Used by ms_stepDoneIndicator in layout/ms_step_tab |
Expand Down
Binary file modified gifs/error-on-tabs.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added gifs/stepper-feedback.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@

POM_GROUP_ID=com.stepstone.stepper
POM_ARTIFACT_ID=material-stepper
POM_VERSION=3.1.0
POM_VERSION=3.2.0
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
import android.widget.LinearLayout;

import com.stepstone.stepper.adapter.StepAdapter;
import com.stepstone.stepper.internal.feedback.StepperFeedbackType;
import com.stepstone.stepper.internal.feedback.StepperFeedbackTypeFactory;
import com.stepstone.stepper.internal.type.AbstractStepperType;
import com.stepstone.stepper.internal.type.StepperTypeFactory;
import com.stepstone.stepper.internal.util.AnimationUtil;
Expand Down Expand Up @@ -222,10 +224,14 @@ public void goToPrevStep() {

private int mTypeIdentifier = AbstractStepperType.PROGRESS_BAR;

private int mFeedbackTypeMask = StepperFeedbackType.NONE;

private StepAdapter mStepAdapter;

private AbstractStepperType mStepperType;

private StepperFeedbackType mStepperFeedbackType;

private int mCurrentStepPosition;

private boolean mShowErrorStateEnabled;
Expand All @@ -234,6 +240,8 @@ public void goToPrevStep() {

private boolean mTabNavigationEnabled;

private boolean mInProgress;

@StyleRes
private int mStepperLayoutTheme;

Expand All @@ -243,7 +251,7 @@ public void goToPrevStep() {
private OnClickListener mOnBackClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
onPrevious();
onBackClicked();
}
};

Expand Down Expand Up @@ -370,6 +378,22 @@ public void proceed() {
}
}

/**
* To be called when the user wants to go to the previous step.
*/
public void onBackClicked() {
Step step = findCurrentStep();

updateErrorFlagWhenGoingBack();

OnBackClickedCallback onBackClickedCallback = new OnBackClickedCallback();
if (step instanceof BlockingStep) {
((BlockingStep) step).onBackClicked(onBackClickedCallback);
} else {
onBackClickedCallback.goToPrevStep();
}
}

/**
* Sets the current step to the one at the provided index.
* This does not verify the current step.
Expand All @@ -385,6 +409,11 @@ public void setCurrentStepPosition(int currentStepPosition) {
onUpdate(currentStepPosition, true);
}

/**
* Returns the position of the currently selected step.
*
* @return position of the currently selected step
*/
public int getCurrentStepPosition() {
return mCurrentStepPosition;
}
Expand All @@ -397,6 +426,18 @@ public void setCompleteButtonVerificationFailed(boolean verificationFailed) {
mCompleteNavigationButton.setVerificationFailed(verificationFailed);
}

public void setNextButtonEnabled(boolean enabled) {
mNextNavigationButton.setEnabled(enabled);
}

public void setCompleteButtonEnabled(boolean enabled) {
mCompleteNavigationButton.setEnabled(enabled);
}

public void setBackButtonEnabled(boolean enabled) {
mBackNavigationButton.setEnabled(enabled);
}

/**
* Set whether when going backwards should clear the error state from the Tab. Default is <code>false</code>.
*
Expand Down Expand Up @@ -496,6 +537,40 @@ public void updateErrorFlag(boolean hasError) {
mStepperType.setErrorFlag(mCurrentStepPosition, hasError);
}

/**
* Shows a progress indicator. This does not have to be a progress bar and it depends on chosen stepper feedback types.
* @param progressMessage optional progress message if supported by the selected types
*/
public void showProgress(@NonNull String progressMessage) {
mInProgress = true;
mStepperFeedbackType.showProgress(progressMessage);
}

/**
* Hides the progress indicator.
*/
public void hideProgress() {
mInProgress = false;
mStepperFeedbackType.hideProgress();
}

/**
* Checks if there's an ongoing operation i.e. if {@link #showProgress(String)} was called and not followed by {@link #hideProgress()} yet.
* @return true if in progress, false otherwise
*/
public boolean isInProgress() {
return mInProgress;
}

/**
* Sets the mask for the stepper feedback type.
* @param feedbackTypeMask step feedback type mask, should contain one or more flags from {@link StepperFeedbackType}
*/
public void setFeedbackType(int feedbackTypeMask) {
mFeedbackTypeMask = feedbackTypeMask;
mStepperFeedbackType = StepperFeedbackTypeFactory.createType(mFeedbackTypeMask, this);
}

@SuppressWarnings("RestrictedApi")
private void init(AttributeSet attrs, @AttrRes int defStyleAttr) {
initDefaultValues();
Expand Down Expand Up @@ -523,6 +598,7 @@ public boolean onTouch(View view, MotionEvent motionEvent) {
mTabsContainer.setVisibility(GONE);

mStepperType = StepperTypeFactory.createType(mTypeIdentifier, this);
mStepperFeedbackType = StepperFeedbackTypeFactory.createType(mFeedbackTypeMask, this);
}

private void initNavigation() {
Expand Down Expand Up @@ -645,7 +721,11 @@ private void extractValuesFromAttributes(AttributeSet attrs, @AttrRes int defSty
mShowErrorStateEnabled = a.getBoolean(R.styleable.StepperLayout_ms_showErrorStateEnabled, mShowErrorStateEnabled);

if (a.hasValue(R.styleable.StepperLayout_ms_stepperType)) {
mTypeIdentifier = a.getInt(R.styleable.StepperLayout_ms_stepperType, DEFAULT_TAB_DIVIDER_WIDTH);
mTypeIdentifier = a.getInt(R.styleable.StepperLayout_ms_stepperType, AbstractStepperType.PROGRESS_BAR);
}

if (a.hasValue(R.styleable.StepperLayout_ms_stepperFeedbackType)) {
mFeedbackTypeMask = a.getInt(R.styleable.StepperLayout_ms_stepperFeedbackType, StepperFeedbackType.NONE);
}

mShowErrorStateOnBackEnabled = a.getBoolean(R.styleable.StepperLayout_ms_showErrorStateOnBack, false);
Expand Down Expand Up @@ -678,19 +758,6 @@ private Step findCurrentStep() {
return mStepAdapter.findStep(mCurrentStepPosition);
}

private void onPrevious() {
Step step = findCurrentStep();

updateErrorFlagWhenGoingBack();

OnBackClickedCallback onBackClickedCallback = new OnBackClickedCallback();
if (step instanceof BlockingStep) {
((BlockingStep) step).onBackClicked(onBackClickedCallback);
} else {
onBackClickedCallback.goToPrevStep();
}
}

private void updateErrorFlagWhenGoingBack() {
updateErrorFlag(mShowErrorStateOnBackEnabled && mStepperType.getErrorAtPosition(mCurrentStepPosition));
}
Expand Down
Loading

0 comments on commit 48d8473

Please sign in to comment.