package com.espian.showcaseview;
import android.app.Activity;
import android.content.Context;
import android.os.Handler;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.List;
public class ShowcaseViews {
private final List<ShowcaseView> views = new ArrayList<ShowcaseView>();
private final List<float[]> animations = new ArrayList<float[]>();
private final Activity activity;
private OnShowcaseAcknowledged showcaseAcknowledgedListener = new OnShowcaseAcknowledged() {
@Override
public void onShowCaseAcknowledged(ShowcaseView showcaseView) {
//DEFAULT LISTENER - DOESN'T DO ANYTHING!
}
};
private static final int ABSOLUTE_COORDINATES = 0;
private static final int RELATIVE_COORDINATES = 1;
public interface OnShowcaseAcknowledged {
void onShowCaseAcknowledged(ShowcaseView showcaseView);
}
public ShowcaseViews(Activity activity) {
this.activity = activity;
}
public ShowcaseViews(Activity activity, OnShowcaseAcknowledged acknowledgedListener) {
this(activity);
this.showcaseAcknowledgedListener = acknowledgedListener;
}
public ShowcaseViews addView(ItemViewProperties properties) {
ShowcaseViewBuilder builder = new ShowcaseViewBuilder(activity)
.setText(properties.titleResId, properties.messageResId)
.setShowcaseIndicatorScale(properties.scale)
.setConfigOptions(properties.configOptions);
if (showcaseActionBar(properties)) {
builder.setShowcaseItem(properties.itemType, properties.id, activity);
} else if (properties.id == ItemViewProperties.ID_NO_SHOWCASE) {
builder.setShowcaseNoView();
} else {
builder.setShowcaseView(activity.findViewById(properties.id));
}
ShowcaseView showcaseView = builder.build();
showcaseView.overrideButtonClick(createShowcaseViewDismissListener(showcaseView));
views.add(showcaseView);
animations.add(null);
return this;
}
/**
* Add an animated gesture to the view at position viewIndex.
*
* @param viewIndex The position of the view the gesture should be added to (beginning with 0
* for the view which had been added as the first one)
* @param offsetStartX x-offset of the start position
* @param offsetStartY y-offset of the start position
* @param offsetEndX x-offset of the end position
* @param offsetEndY y-offset of the end position
* @see com.espian.showcaseview.ShowcaseView#animateGesture(float, float, float, float)
* @see com.espian.showcaseview.ShowcaseViews#addAnimatedGestureToView(int, float, float, float,
* float, boolean)
*/
public void addAnimatedGestureToView(int viewIndex, float offsetStartX, float offsetStartY,
float offsetEndX, float offsetEndY) throws IndexOutOfBoundsException {
addAnimatedGestureToView(viewIndex, offsetStartX, offsetStartY, offsetEndX, offsetEndY,
false);
}
/**
* Add an animated gesture to the view at position viewIndex.
*
* @param viewIndex The position of the view the gesture should be added to (beginning
* with 0 for the view which had been added as the first one)
* @param startX x-coordinate or x-offset of the start position
* @param startY y-coordinate or x-offset of the start position
* @param endX x-coordinate or x-offset of the end position
* @param endY y-coordinate or x-offset of the end position
* @param absoluteCoordinates If true, this will use absolute coordinates instead of coordinates
* relative to the center of the showcased view
*/
public void addAnimatedGestureToView(int viewIndex, float startX, float startY, float endX,
float endY, boolean absoluteCoordinates) throws IndexOutOfBoundsException {
animations.remove(viewIndex);
animations.add(viewIndex,
new float[]{absoluteCoordinates ? ABSOLUTE_COORDINATES : RELATIVE_COORDINATES,
startX, startY, endX, endY});
}
private boolean showcaseActionBar(ItemViewProperties properties) {
return properties.itemType > ItemViewProperties.ID_NOT_IN_ACTIONBAR;
}
private View.OnClickListener createShowcaseViewDismissListener(
final ShowcaseView showcaseView) {
return new View.OnClickListener() {
@Override
public void onClick(View v) {
showcaseView.onClick(showcaseView); //Needed for TYPE_ONE_SHOT
int fadeOutTime = showcaseView.getConfigOptions().fadeOutDuration;
if (fadeOutTime > 0) {
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
showNextView(showcaseView);
}
}, fadeOutTime);
} else {
showNextView(showcaseView);
}
}
};
}
private void showNextView(ShowcaseView showcaseView) {
if (views.isEmpty()) {
showcaseAcknowledgedListener.onShowCaseAcknowledged(showcaseView);
} else {
show();
}
}
public void show() {
if (views.isEmpty()) {
return;
}
final ShowcaseView view = views.get(0);
boolean hasShot = activity
.getSharedPreferences(ShowcaseView.PREFS_SHOWCASE_INTERNAL, Context.MODE_PRIVATE)
.getBoolean("hasShot" + view.getConfigOptions().showcaseId, false);
if (hasShot && view.getConfigOptions().shotType == ShowcaseView.TYPE_ONE_SHOT) {
// The showcase has already been shot once, so we don't need to do show it again.
view.setVisibility(View.GONE);
views.remove(0);
animations.remove(0);
view.getConfigOptions().fadeOutDuration = 0;
view.performButtonClick();
return;
}
view.setVisibility(View.INVISIBLE);
((ViewGroup) activity.getWindow().getDecorView()).addView(view);
view.show();
float[] animation = animations.get(0);
if (animation != null) {
view.animateGesture(animation[1], animation[2], animation[3], animation[4],
animation[0] == ABSOLUTE_COORDINATES);
}
views.remove(0);
animations.remove(0);
}
public boolean hasViews() {
return !views.isEmpty();
}
public static class ItemViewProperties {
public static final int ID_NO_SHOWCASE = -2202;
public static final int ID_NOT_IN_ACTIONBAR = -1;
public static final int ID_SPINNER = 0;
public static final int ID_TITLE = 1;
public static final int ID_OVERFLOW = 2;
private static final float DEFAULT_SCALE = 1f;
protected final int titleResId;
protected final int messageResId;
protected final int id;
protected final int itemType;
protected final float scale;
protected final ShowcaseView.ConfigOptions configOptions;
public ItemViewProperties(int titleResId, int messageResId) {
this(ID_NO_SHOWCASE, titleResId, messageResId, ID_NOT_IN_ACTIONBAR, DEFAULT_SCALE,
null);
}
public ItemViewProperties(int id, int titleResId, int messageResId) {
this(id, titleResId, messageResId, ID_NOT_IN_ACTIONBAR, DEFAULT_SCALE, null);
}
public ItemViewProperties(int id, int titleResId, int messageResId, float scale) {
this(id, titleResId, messageResId, ID_NOT_IN_ACTIONBAR, scale, null);
}
public ItemViewProperties(int id, int titleResId, int messageResId, int itemType) {
this(id, titleResId, messageResId, itemType, DEFAULT_SCALE, null);
}
public ItemViewProperties(int id, int titleResId, int messageResId, int itemType,
float scale) {
this(id, titleResId, messageResId, itemType, scale, null);
}
public ItemViewProperties(int titleResId, int messageResId,
ShowcaseView.ConfigOptions configOptions) {
this(ID_NO_SHOWCASE, titleResId, messageResId, ID_NOT_IN_ACTIONBAR, DEFAULT_SCALE,
configOptions);
}
public ItemViewProperties(int id, int titleResId, int messageResId,
ShowcaseView.ConfigOptions configOptions) {
this(id, titleResId, messageResId, ID_NOT_IN_ACTIONBAR, DEFAULT_SCALE, configOptions);
}
public ItemViewProperties(int id, int titleResId, int messageResId, float scale,
ShowcaseView.ConfigOptions configOptions) {
this(id, titleResId, messageResId, ID_NOT_IN_ACTIONBAR, scale, configOptions);
}
public ItemViewProperties(int id, int titleResId, int messageResId, int itemType,
ShowcaseView.ConfigOptions configOptions) {
this(id, titleResId, messageResId, itemType, DEFAULT_SCALE, configOptions);
}
public ItemViewProperties(int id, int titleResId, int messageResId, int itemType,
float scale, ShowcaseView.ConfigOptions configOptions) {
this.id = id;
this.titleResId = titleResId;
this.messageResId = messageResId;
this.itemType = itemType;
this.scale = scale;
this.configOptions = configOptions;
}
}
}