From afd025d4dd8bb23425c9f6262155052f3f7e404f Mon Sep 17 00:00:00 2001 From: Darek Deoniziak Date: Mon, 26 Sep 2016 12:31:58 +0200 Subject: [PATCH 1/4] initial commit for fork ShowcaseViews --- .../amlcurran/showcaseview/ShowcaseViews.java | 338 ++++++++++++++++++ 1 file changed, 338 insertions(+) create mode 100644 library/src/main/java/com/github/amlcurran/showcaseview/ShowcaseViews.java diff --git a/library/src/main/java/com/github/amlcurran/showcaseview/ShowcaseViews.java b/library/src/main/java/com/github/amlcurran/showcaseview/ShowcaseViews.java new file mode 100644 index 000000000..f2f0f06c3 --- /dev/null +++ b/library/src/main/java/com/github/amlcurran/showcaseview/ShowcaseViews.java @@ -0,0 +1,338 @@ +package com.github.amlcurran.showcaseview; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Build; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; + +import com.github.amlcurran.showcaseview.targets.ViewTarget; + +import java.util.ArrayList; +import java.util.List; + +/** + * Wrapper for {@link ShowcaseView} allows to showcase multiple areas one after another. + */ +public class ShowcaseViews implements OnShowcaseEventListener { + + private static final String TAG = ShowcaseViews.class.getSimpleName(); + + public static final int SHOT_MODE_MULTIPLE = 0; + public static final int SHOT_MODE_SINGLE = 1; + public static final int SHOT_MODE_ONCE_EACH_VIEW = 2; + + private final List views; + private final Activity activity; + private final int showcaseStyleResId; + private final ShowcaseViewsListener listener; + private boolean disableGuidedView; + private ShowcaseView showcaseView = null; + private int shotMode; + + private ViewGroup topViewGroup; + + private ShowcaseViews(Builder builder) { + this.activity = builder.activity; + this.views = builder.views; + this.showcaseStyleResId = builder.showcaseStyleResId; + this.listener = builder.listener; + this.disableGuidedView = builder.disableGuidedView; + this.shotMode = builder.shotMode; + topViewGroup = (ViewGroup) activity.getWindow().getDecorView().findViewById(android.R.id.content); + show(); + } + + /** + * Enables/Disables all child views in a view group. + * + * @param viewGroup the view group + * @param enabled true to enable, false to disable + * the views. + */ + public void enableDisableViewGroup(ViewGroup viewGroup, boolean enabled) { + int childCount = viewGroup.getChildCount(); + for (int i = 0; i < childCount; i++) { + View view = viewGroup.getChildAt(i); + view.setEnabled(enabled); + if (view instanceof ViewGroup) { + enableDisableViewGroup((ViewGroup) view, enabled); + } + } + } + + private boolean didShowLastGuide() { + ViewProperties viewProperties = views.get(views.size() - 1); + int shotId = viewProperties.id; + + return didShowGuide(shotId); + } + + private boolean didShowFirstGuide() { + ViewProperties viewProperties = views.get(0); + int shotId = viewProperties.id; + + return didShowGuide(shotId); + } + + private boolean didShowGuide(int shotId) { + SharedPreferences settings = activity.getSharedPreferences("showcase_internal", Context.MODE_PRIVATE); + return settings.getBoolean("hasShot" + shotId, false); + } + + /** + * Showcases will be shown in the order they where added, continuing when the button is pressed + */ + public void show() { + if (views != null && !views.isEmpty()) { + switch (shotMode) { + case (SHOT_MODE_MULTIPLE): + prepareTopViewGroup(); + if (listener != null) { + listener.onShowcaseStart(); + } + showNextGuide(); + break; + case (SHOT_MODE_SINGLE): + if (!didShowFirstGuide()) { + prepareTopViewGroup(); + if (listener != null) { + listener.onShowcaseStart(); + } + showNextGuide(); + } else if (listener != null) { + listener.onShowcaseEnd(false); + } + break; + case (SHOT_MODE_ONCE_EACH_VIEW): + if (!didShowLastGuide()) { + prepareTopViewGroup(); + if (listener != null) { + listener.onShowcaseStart(); + } + showNextGuide(); + } else if (listener != null) { + listener.onShowcaseEnd(false); + } + break; + } + } + } + + public void hide() { + restoreTopViewGroup(); + if (showcaseView != null) + showcaseView.hide(); + } + + public boolean isShowing() { + if (showcaseView == null) + return false; + return showcaseView.isShowing(); + } + + private void prepareTopViewGroup() { + if (disableGuidedView) { + enableDisableViewGroup(topViewGroup, false); + } + } + + private void showNextGuide() { + if (views.isEmpty()) { + restoreTopViewGroup(); + if (listener != null) + listener.onShowcaseEnd(true); + return; + } + + final ViewProperties viewProperties = views.get(0); + showcaseView = null; + ShowcaseView.Builder builder = new ShowcaseView.Builder(activity, true) + .setTarget(new ViewTarget(viewProperties.id, activity)) + .setContentTitle(viewProperties.title) + .setContentText(viewProperties.message) + .setShowcaseEventListener(this) + .setStyle(showcaseStyleResId); + + if (shotMode != SHOT_MODE_MULTIPLE) { + builder.singleShot(viewProperties.id); + } + + showcaseView = builder.build(); + + if (showcaseView.getVisibility() != View.VISIBLE) { + removeCurrentGuide(); + showNextGuide(); + } + } + + private void restoreTopViewGroup() { + if (disableGuidedView) { + enableDisableViewGroup(topViewGroup, true); + } + } + + @Override + public void onShowcaseViewHide(ShowcaseView showcaseView) { + removeCurrentGuide(); + showNextGuide(); + } + + private void removeCurrentGuide() { + try { + ViewProperties vp = views.get(0); + views.remove(vp); + vp = null; + } catch (Exception e) { + Log.e(TAG, e.getLocalizedMessage(), e); + } + } + + @Override + public void onShowcaseViewDidHide(ShowcaseView showcaseView) { + // nothing to do here + } + + @Override + public void onShowcaseViewShow(ShowcaseView showcaseView) { + // nothing to do here + } + + @Override + public void onShowcaseViewTouchBlocked(MotionEvent motionEvent) { + // nothing to do here + } + + @Override + protected void finalize() throws Throwable { + showcaseView = null; + + super.finalize(); + } + + /** + * Used for views on the ActionBar + */ + public class ItemViewProperties extends ViewProperties { + public static final int ID_SPINNER = 0; + public static final int ID_TITLE = 0; + protected final int itemType; + + public ItemViewProperties(int id, String title, String message, int itemType) { + super(id, title, message); + this.itemType = itemType; + } + } + + /** + * Used for all views except those on the ActionBar + */ + public static class ViewProperties { + protected final CharSequence title; + protected final CharSequence message; + protected final int id; + + public ViewProperties(int id, CharSequence title, CharSequence message) { + this.id = id; + this.title = title; + this.message = message; + } + } + + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + public static void dimView(View view, float alphaValue) { + ApiUtils apiUtils = new ApiUtils(); + if (apiUtils.isCompatWithHoneycomb()) { + view.setAlpha(alphaValue); + } + } + + public static class Builder { + private final Activity activity; + private int showcaseStyleResId; + private ShowcaseViewsListener listener; + private boolean disableGuidedView; + private int shotMode = SHOT_MODE_MULTIPLE; + + private List views = new ArrayList(); + + /** + * @param activity The activity containing the views you wish to showcase + */ + public Builder(Activity activity) { + this.activity = activity; + } + + /** + * @param showcaseStyleResId Must be the layout of a ShowcaseView - use this to style your showcase + */ + public Builder setStyle(int showcaseStyleResId) { + this.showcaseStyleResId = showcaseStyleResId; + return this; + } + + /** + * @param listener Provides callbacks before showing first showcase and after showing last. + */ + public Builder setListener(ShowcaseViewsListener listener) { + this.listener = listener; + return this; + } + + public Builder setDisableViewGroup() { + disableGuidedView = true; + return this; + } + + public Builder addView(ItemViewProperties properties) { + views.add(properties); + return this; + } + + public Builder addView(ViewProperties properties) { + views.add(properties); + return this; + } + + public Builder addViews(List views, boolean override) { + if (override) + views.clear(); + views.addAll(views); + return this; + } + + /** + *

Change mode to either display showcases multiple times, single or each one once.

+ *

Available modes are:

+ *
{@link #SHOT_MODE_MULTIPLE} - default mode, will always show all guides.
+ *
{@link #SHOT_MODE_SINGLE} - all group of showcase views will be shown only once, + * even if user will not finish the guide.
+ *
{@link #SHOT_MODE_ONCE_EACH_VIEW} - each one view will be shown once, + * if user will not finish the guide the showcase will start from last, not shown view
+ * + * @param mode a mode to select + */ + public Builder setShotMode(int mode) { + if (mode == SHOT_MODE_MULTIPLE || mode == SHOT_MODE_SINGLE || mode == SHOT_MODE_ONCE_EACH_VIEW) { + shotMode = mode; + } + return this; + } + + /** + * Showcases will be shown in the order they where added, continuing when the button is pressed + */ + public ShowcaseViews show() { + return new ShowcaseViews(this); + } + } + + public interface ShowcaseViewsListener { + public void onShowcaseStart(); + public void onShowcaseEnd(boolean hadViews); + } +} From 8a6f858b5bf0fa52ea775a98225b601f70b438a8 Mon Sep 17 00:00:00 2001 From: DarekDeo Date: Mon, 26 Sep 2016 12:51:32 +0200 Subject: [PATCH 2/4] showcaseviews fork readme just an updated readme --- README.md | 125 ++++++++++++++---------------------------------------- 1 file changed, 33 insertions(+), 92 deletions(-) diff --git a/README.md b/README.md index a3f82021f..c6a62a944 100644 --- a/README.md +++ b/README.md @@ -1,104 +1,45 @@ -ShowcaseView +ShowcaseViews --- -The ShowcaseView (SCV) library is designed to highlight and showcase specific parts of apps to the user with a distinctive and attractive overlay. This library is great for pointing out points of interest for users, gestures, or obscure but useful items. - -| Holo | "New style" | Material | -| --- | --- | --- | -| ![Holo style showcaseview](./example2@2x.png) | ![new style showcaseview](./example@2x.png) | ![Material style showcaseview](./material.png) | - -The library is based on the "Cling" view found in the Launcher on Ice-Cream Sandwich and Jelly Bean. - -Project set-up -==== - -**ShowcaseView currently supports API LEVEL 11+** - -If you're using a Gradle-based project, then you can add SCV as a dependency directly: - -~~~ -compile 'com.github.amlcurran.showcaseview:library:5.4.3' -~~~ - -If you're using Maven (but not Gradle), you can add the APKlib as a dependency: - -~~~ - - com.github.amlcurran.showcaseview - library - 5.4.3 - apklib - -~~~ - -If you're using a standard project without either Maven or Gradle, you'll have to download the project, and the add the library manually to your project. - +It's little fork/wrapper of great https://github.com/amlcurran/ShowcaseView +It allows showing multiple showcase views one after another. Usage ==== -To use ShowcaseView, use the Builder pattern. - -As an example: +Just like in classic ShowcaseView, to use ShowcaseViews use Builder pattern: ~~~ -new ShowcaseView.Builder(this) - .setTarget(new ActionViewTarget(this, ActionViewTarget.Type.HOME)) - .setContentTitle("ShowcaseView") - .setContentText("This is highlighting the Home button") - .hideOnTouchOutside() - .build(); +showcaseViews = new ShowcaseViews.Builder(this) + .setStyle(R.style.CustomShowcaseTheme) + .setShotMode(ShowcaseViews.SHOT_MODE_MULTIPLE) + .addView(new ShowcaseViews.ViewProperties( + R.id.first_target, + "title of first target", + "content description of first target") + ) + .addView(new ShowcaseViews.ViewProperties( + R.id.second_target, + "title of second target", + "content description of second target") + ) + .setListener(new ShowcaseViews.ShowcaseViewsListener() { + @Override + public void onShowcaseStart() { + // do some stuff before first target shows + } + + @Override + public void onShowcaseEnd(boolean hadViews) { + // do some stuff after last target shows + } + }) + .show(); ~~~ - -You can use styles to customise how a ShowcaseView looks. I'll write more documentation soon, but for now, check out the sample project's [styles](https://github.com/amlcurran/ShowcaseView/blob/master/sample/src/main/res/values/styles.xml). - -Sample Project ----- -There's a sample project available which you can find in the project, or as an app on the [Google Play Store](https://play.google.com/store/apps/details?id=com.espian.showcaseview.sample). - -What's the legacy branch? ----- -The [legacy branch](https://github.com/amlcurran/ShowcaseView/tree/legacy) is still available for people to use. This has more features than the master branch, but it more unwieldy to use and less stable. I don't support it at all - you'll have to build and compile it yourself. It isn't available on Maven Central either. - -Is it worth using? ----- -Perhaps. Why not ask -[Google](https://github.com/googlecast/CastVideos-android), [iPlayer Radio](https://play.google.com/store/apps/details?id=uk.co.bbc.android.iplayerradio), -or [AllCast](https://play.google.com/store/apps/details?id=com.koushikdutta.cast), which each use the library? - -Previous users include The Guardian and HaxSync - -What's missing in v5 ---- - -- ShowcaseViews: the class which queues up ShowcaseViews in a tutorial-type method. I never -really liked this class (generally, you should use SCV sparingly); I'll add it back in based on -the Builder class when I can. -- Ghostly hand: this has gone for now until I can test-drive it back in. -- Scale multiplier: this has gone for simplicity - if people really loved it I'll add in back in - -FAQs ---- - -**Where has X feature gone?** - -Look one paragraph up! - -**Waaaah, but I really liked feature X!!!** - -Switch to the legacy branch and use that one then! All legacy features are in there. - -**What happened to all the other constructors?** - -Gone. You should be using the new Target API. - -**What if I want to add feature X?** - -At the moment, I'm not taking any feature requests. It's unlikely I'll take many anyway, -unless I feel they are both useful and well tested. If you have some cosmetic tweak then I don't -want that added into the library as *another* option. But, if you need to make a tweak to the -library to add such a tweak to your own, overridden ShowcaseView then that is totally great. - +Shot modes: +ShowcaseViews.SHOT_MODE_MULTIPLE +ShowcaseViews.SHOT_MODE_SINGLE +ShowcaseViews.SHOT_MODE_ONCE_EACH_VIEW Copyright and Licensing ---- From d493a43f9253fa0dd0475543c83a739e88a592d5 Mon Sep 17 00:00:00 2001 From: DarekDeo Date: Mon, 26 Sep 2016 12:52:08 +0200 Subject: [PATCH 3/4] Update README.md --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index c6a62a944..6450c705c 100644 --- a/README.md +++ b/README.md @@ -36,10 +36,6 @@ showcaseViews = new ShowcaseViews.Builder(this) }) .show(); ~~~ -Shot modes: -ShowcaseViews.SHOT_MODE_MULTIPLE -ShowcaseViews.SHOT_MODE_SINGLE -ShowcaseViews.SHOT_MODE_ONCE_EACH_VIEW Copyright and Licensing ---- From 82d80e5f383727ca72ec0243d0b8037a6f59cfbe Mon Sep 17 00:00:00 2001 From: Darek Deoniziak Date: Mon, 26 Sep 2016 12:53:37 +0200 Subject: [PATCH 4/4] initial commit for ShowcaseViews wrapper --- .../com/github/amlcurran/showcaseview/ShowcaseViews.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/library/src/main/java/com/github/amlcurran/showcaseview/ShowcaseViews.java b/library/src/main/java/com/github/amlcurran/showcaseview/ShowcaseViews.java index f2f0f06c3..acca85db9 100644 --- a/library/src/main/java/com/github/amlcurran/showcaseview/ShowcaseViews.java +++ b/library/src/main/java/com/github/amlcurran/showcaseview/ShowcaseViews.java @@ -17,6 +17,8 @@ /** * Wrapper for {@link ShowcaseView} allows to showcase multiple areas one after another. + * + * Created by Dariusz Deoniziak (darekdeoniziak@gmail.com) */ public class ShowcaseViews implements OnShowcaseEventListener { @@ -69,17 +71,17 @@ private boolean didShowLastGuide() { ViewProperties viewProperties = views.get(views.size() - 1); int shotId = viewProperties.id; - return didShowGuide(shotId); + return didShowGuideFor(shotId); } private boolean didShowFirstGuide() { ViewProperties viewProperties = views.get(0); int shotId = viewProperties.id; - return didShowGuide(shotId); + return didShowGuideFor(shotId); } - private boolean didShowGuide(int shotId) { + public boolean didShowGuideFor(int shotId) { SharedPreferences settings = activity.getSharedPreferences("showcase_internal", Context.MODE_PRIVATE); return settings.getBoolean("hasShot" + shotId, false); }