diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..905ab1c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,14 @@
+*.iml
+.gradle
+/local.properties
+/.idea/workspace.xml
+/.idea/libraries
+/.idea/vcs.xml
+/.idea/misc.xml
+.DS_Store
+/build
+/captures
+.idea/vcs.xml
+app/libs/
+/.idea
+
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..f770fc9
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,60 @@
+#
+# Build configuration for TRAVIS CI
+#
+
+# Disabling sudo moves build to the Container Based Infrastructure on Travis CI
+sudo: false
+
+language: android
+jdk: oraclejdk8
+
+env:
+ global:
+ - MALLOC_ARENA_MAX=2
+ - ADB_INSTALL_TIMEOUT=10
+ - ANDROID_API_LEVEL=25
+ - ANDROID_BUILD_TOOLS_VERSION=25.0.2
+ - ANDROID_ABI=armeabi-v7a
+ - ANDROID_TAG=google_apis
+
+android:
+ components:
+ - platform-tools
+ - tools
+ - tools
+ - android-$ANDROID_API_LEVEL
+ - build-tools-$ANDROID_BUILD_TOOLS_VERSION
+ # For Google Maps API v1
+ - addon-google_apis-google-$ANDROID_API_LEVEL
+ # Google Play Services
+ - extra-google-google_play_services
+ # Support library
+ - extra-android-support
+ # Latest artifacts in local repository
+ - extra-google-m2repository
+ - extra-android-m2repository
+ # Specify at least one system image
+ - sys-img-armeabi-v7a-android-$ANDROID_API_LEVEL
+ - sys-img-armeabi-v7a-addon-google_apis-google-$ANDROID_API_LEVEL
+
+ licenses:
+ - 'android-sdk-preview-license-.+'
+ - 'android-sdk-license-.+'
+ - 'google-gdk-license-.+'
+ - '.+'
+
+before_install:
+ - pip install --user codecov
+
+script:
+ - sh ci.sh
+
+after_success:
+ - codecov
+
+notifications:
+ email: true
+ slack: myntra:3GgFvhHOLMEe3WIVzuoFUW8Y
+
+cache: false
+sudo: required
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..8dada3e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "{}"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright {yyyy} {name of copyright owner}
+
+ 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.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..df329a8
--- /dev/null
+++ b/README.md
@@ -0,0 +1,24 @@
+# CoachMarks (Work In Progress)
+
+[![Platform](https://img.shields.io/badge/platform-android-green.svg)](http://developer.android.com/index.html)
+![SDK](https://img.shields.io/badge/SDK-16%2B-green.svg)
+![Release](https://img.shields.io/badge/release-0.1-green.svg)
+[![Build Status](https://travis-ci.org/myntra/CoachMarks.svg?branch=master)](https://travis-ci.org/myntra/CoachMarks)
+[![CircleCI](https://circleci.com/gh/myntra/CoachMarks.svg?style=svg)](https://circleci.com/gh/myntra/CoachMarks)
+
+License
+-------
+
+ Copyright Manjunath Chandrashekar & Mudit Pant 2017
+
+ 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.
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..b71d312
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,149 @@
+import com.android.build.gradle.internal.tasks.AndroidTestTask
+
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+apply from: 'dependencies.gradle'
+
+buildscript {
+ // Gradle will not find vars defined in an external file when referring to them
+ // in the buildscript block, unless you link it from the buildscript block, too.
+ apply from: 'dependencies.gradle'
+
+ repositories {
+ jcenter()
+
+ maven { url "https://jitpack.io" }
+ }
+
+ dependencies {
+ classpath gradlePlugins.aptPlugin
+ classpath gradlePlugins.androidToolsPlugin
+ classpath gradlePlugins.butterKnifePlugin
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ jcenter()
+
+ maven { url "https://jitpack.io" }
+ }
+
+ // Workaround to prevent Gradle from stealing focus from other apps during tests run/etc.
+ // https://gist.github.com/artem-zinnatullin/4c250e04636e25797165
+ tasks.withType(JavaForkOptions) {
+ jvmArgs '-Djava.awt.headless=true'
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
+
+ext.preDexLibs = !project.hasProperty('disablePreDex')
+
+subprojects {
+
+ project.plugins.whenPluginAdded { plugin ->
+ if ('com.android.build.gradle.AppPlugin'.equals(plugin.class.name) ||
+ 'com.android.build.gradle.LibraryPlugin'.equals(plugin.class.name)) {
+ // enable or disable pre-dexing
+ project.android.dexOptions.preDexLibraries = rootProject.ext.preDexLibs
+ }
+ }
+
+ plugins.apply('pmd')
+ pmd {
+ toolVersion = '5.4.1'
+ }
+ task pmd(type: Pmd) {
+ ignoreFailures = true
+ ruleSetFiles = project.files(rootProject.file("config/pmd/pmd.xml"))
+ ruleSets = []
+
+ source = fileTree('src/main/java')
+ source 'src'
+ include '**/*.java'
+ exclude '**/gen/**'
+
+ reports {
+ xml.enabled = false
+ html.enabled = true
+ xml {
+ destination "$project.buildDir/reports/pmd/pmd.xml"
+ }
+ html {
+ destination "$project.buildDir/reports/pmd/pmd.html"
+ }
+ }
+ }
+
+ plugins.apply('findbugs')
+ task findbugs(type: FindBugs) {
+ ignoreFailures = true
+ effort = "max"
+ reportLevel = "high"
+ excludeFilter = rootProject.file('config/findbugs/findbugs.xml')
+ classes = files("${project.rootDir}/app/build/intermediates/classes")
+
+ source = fileTree('src/main/java')
+ source 'src'
+ include '**/*.java'
+ exclude '**/gen/**'
+
+ reports {
+ xml.enabled = false
+ html.enabled = true
+
+ xml {
+ destination "$project.buildDir/reports/findbugs/findbugs.xml"
+ withMessages = true
+ }
+ html {
+ destination "$project.buildDir/reports/findbugs/findbugs.html"
+ }
+ }
+ classpath = files()
+ }
+
+ plugins.apply('checkstyle')
+ checkstyle {
+ toolVersion = '6.7'
+ }
+ task checkstyle(type: Checkstyle) {
+ configFile rootProject.file('config/checkstyle/checkstyle.xml')
+ configProperties.checkstyleSuppressionsPath = file("${project.rootDir}/code_quality/checkstyle/suppressions.xml").absolutePath
+
+ ignoreFailures true
+ showViolations true
+
+ source 'src'
+ include '**/*.java'
+ exclude '**/gen/**'
+ classpath = files()
+ }
+
+ afterEvaluate {
+ tasks.findByName('pmd').dependsOn('assemble')
+ tasks.findByName('findbugs').dependsOn('assemble')
+
+ def checkTask = tasks.findByName('check')
+
+ checkTask.dependsOn('pmd')
+ //checkTask.dependsOn('findbugs')
+ checkTask.dependsOn('checkstyle')
+ checkTask.dependsOn('lint')
+
+ // Log instrumentation tests results.
+ tasks.withType(AndroidTestTask) { task ->
+ task.doFirst {
+ logging.level = LogLevel.INFO
+ }
+ task.doLast {
+ logging.level = LogLevel.LIFECYCLE
+ }
+ }
+ }
+}
+
diff --git a/ci.sh b/ci.sh
new file mode 100644
index 0000000..a64222b
--- /dev/null
+++ b/ci.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+# Please run it from root project directory
+./gradlew clean build -PdisablePreDex -PwithDexcount
\ No newline at end of file
diff --git a/circle.yml b/circle.yml
new file mode 100644
index 0000000..9daf338
--- /dev/null
+++ b/circle.yml
@@ -0,0 +1,31 @@
+#
+# Build configuration for Circle CI
+#
+general:
+ artifacts:
+ - /home/ubuntu/com.myntra.coachmarks/app/build/outputs/apk/
+
+machine:
+ environment:
+ ANDROID_HOME: /usr/local/android-sdk-linux
+ GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError"'
+ java:
+ version: openjdk8
+
+dependencies:
+ pre:
+ - echo y | android update sdk --no-ui --all --filter "tools,android-25,build-tools-25.0.2,platform-tools,extra-android-m2repository,extra-google-m2repository,extra-google-google_play_services"
+
+#-PdisablePreDex is a must else gradle just dies due to memory limit
+test:
+ override:
+ - (./gradlew assemble -PdisablePreDex):
+ timeout: 1000
+
+#Deploy when tests pass
+deployment:
+ master:
+ branch: master
+ commands:
+ - (./gradlew clean build -PdisablePreDex -PwithDexcount --info):
+ timeout: 720
\ No newline at end of file
diff --git a/coachmarks/.gitignore b/coachmarks/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/coachmarks/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/coachmarks/build.gradle b/coachmarks/build.gradle
new file mode 100644
index 0000000..8d520e7
--- /dev/null
+++ b/coachmarks/build.gradle
@@ -0,0 +1,63 @@
+apply plugin: 'com.android.library'
+apply plugin: 'com.jakewharton.butterknife'
+
+android {
+ compileSdkVersion versions.compileSdk
+ buildToolsVersion versions.buildTools
+
+ defaultConfig {
+ minSdkVersion versions.minSdk
+ targetSdkVersion versions.targetSdk
+ versionCode 1
+ versionName "0.0.1"
+ vectorDrawables.useSupportLibrary = true
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+
+ lintOptions {
+ warningsAsErrors false
+ abortOnError false
+
+ xmlReport false
+ htmlReport true
+ lintConfig file("${project.rootDir}/../code_quality/lint/lint.xml")
+ htmlOutput file("$project.buildDir/reports/lint/lint-result.html")
+ xmlOutput file("$project.buildDir/reports/lint/lint-result.xml")
+ }
+
+}
+
+dependencies {
+ compile fileTree(dir: 'libs', include: ['*.jar'])
+
+ //SUPPORT LIB
+ compile libraries.supportAppCompat
+
+ //Utils
+ compile libraries.zetaUtils
+
+ //PROGRAMMING
+ provided libraries.autoValue
+ annotationProcessor libraries.autoValueParcel
+ compile libraries.butterKnife
+ annotationProcessor libraries.butterKnifeCompiler
+
+ //ANNOTATION
+ compile libraries.jsr305
+ compile libraries.javaxAnnotationApi
+
+ compile(libraries.bundler) {
+ // exclude this because bundler refers to an old version of the support lib
+ exclude group: 'com.google.android'
+ }
+
+ //TESTING
+ testCompile libraries.junit
+
+}
diff --git a/coachmarks/proguard-rules.pro b/coachmarks/proguard-rules.pro
new file mode 100644
index 0000000..353bea2
--- /dev/null
+++ b/coachmarks/proguard-rules.pro
@@ -0,0 +1,17 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /Users/z087205/Library/Android/sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
diff --git a/coachmarks/src/androidTest/java/com/myntra/coachmarks/ApplicationTest.java b/coachmarks/src/androidTest/java/com/myntra/coachmarks/ApplicationTest.java
new file mode 100644
index 0000000..3e27c5b
--- /dev/null
+++ b/coachmarks/src/androidTest/java/com/myntra/coachmarks/ApplicationTest.java
@@ -0,0 +1,13 @@
+package com.myntra.coachmarks;
+
+import android.app.Application;
+import android.test.ApplicationTestCase;
+
+/**
+ * Testing Fundamentals
+ */
+public class ApplicationTest extends ApplicationTestCase {
+ public ApplicationTest() {
+ super(Application.class);
+ }
+}
\ No newline at end of file
diff --git a/coachmarks/src/main/AndroidManifest.xml b/coachmarks/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..d897f98
--- /dev/null
+++ b/coachmarks/src/main/AndroidManifest.xml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/coachmarks/src/main/java/com/myntra/coachmarks/PopUpCoachMark.java b/coachmarks/src/main/java/com/myntra/coachmarks/PopUpCoachMark.java
new file mode 100644
index 0000000..077dce2
--- /dev/null
+++ b/coachmarks/src/main/java/com/myntra/coachmarks/PopUpCoachMark.java
@@ -0,0 +1,357 @@
+package com.myntra.coachmarks;
+
+
+import android.app.Dialog;
+import android.content.Context;
+import android.graphics.Rect;
+import android.graphics.Typeface;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.app.DialogFragment;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.widget.AppCompatTextView;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.Toast;
+
+import com.f2prateek.bundler.FragmentBundlerCompat;
+import com.myntra.coachmarks.builder.CoachMarkBuilder;
+import com.myntra.coachmarks.common.CoachMarkAlignPosition;
+import com.myntra.coachmarks.common.CoachMarkLayoutOrientation;
+import com.myntra.coachmarks.common.CoachMarkTextGravity;
+import com.myntra.coachmarks.providers.DefaultDimensionResourceProvider;
+import com.myntra.coachmarks.providers.DefaultScreenInfoProvider;
+import com.myntra.coachmarks.providers.DefaultStringResourceProvider;
+import com.myntra.coachmarks.providers.DefaultTypeFaceProvider;
+import com.myntra.coachmarks.providers.interfaces.IDimensionResourceProvider;
+import com.myntra.coachmarks.providers.interfaces.IScreenInfoProvider;
+import com.myntra.coachmarks.providers.interfaces.IStringResourceProvider;
+import com.myntra.coachmarks.providers.interfaces.ITypeFaceProvider;
+import com.myntra.coachmarks.ui.common.BaseViews;
+import com.myntra.coachmarks.ui.presentation.IPopUpCoachMarkPresentation;
+import com.myntra.coachmarks.ui.presenter.PopUpCoachMarkPresenter;
+import com.myntra.coachmarks.ui.utils.TransitionUtils;
+
+import butterknife.BindView;
+import zeta.android.utils.view.ViewUtils;
+
+public class PopUpCoachMark extends DialogFragment implements IPopUpCoachMarkPresentation, View.OnClickListener {
+ private static final String TAG = PopUpCoachMark.class.getSimpleName();
+
+ private static final int NO_MARGIN = 0;
+ private static final String ARG_POP_UP_COACH_MARK_BUILDER_PARCEL = "ARG_POP_UP_COACH_MARK_BUILDER_PARCEL";
+
+ private Views mViews;
+ private PopUpCoachMarkPresenter mPopUpCoachMarkPresenter;
+
+ static class Views extends BaseViews {
+
+ @BindView(R2.id.rl_coachmark_parent)
+ RelativeLayout rlCoachMarkParent;
+
+ @BindView(R2.id.tv_coachmark_text)
+ AppCompatTextView tvPopUpCoachMarkText;
+
+ @BindView(R2.id.tv_ok_button)
+ AppCompatTextView tvPopUpDismissButton;
+
+ @BindView(R2.id.v_separator)
+ ImageView vSeparator;
+
+ @BindView(R2.id.iv_coachmark_image)
+ ImageView ivCoachMarkImage;
+
+ @BindView(R2.id.rl_shim_out_view_parent)
+ FrameLayout rlShimOutViewParent;
+
+ @BindView(R2.id.rl_coachmark_text_part)
+ RelativeLayout rlCoachMarkTextPart;
+
+ @BindView(R2.id.ll_coach_mark_pop_up_parent)
+ LinearLayout llPopUpCoachMarkParent;
+
+ @BindView(R2.id.right_bottom_notch)
+ View vRightBottomNotch;
+
+ @BindView(R2.id.left_top_notch)
+ View vLeftTopNotch;
+
+ @BindView(R2.id.v_notch_base_white_left)
+ View vNotchBaseWhiteLeft;
+
+ @BindView(R2.id.v_notch_base_white_top)
+ View vNotchBaseWhiteTop;
+
+ @BindView(R2.id.test)
+ LinearLayout test;
+
+ Views(View root) {
+ super(root);
+ }
+ }
+
+ public static PopUpCoachMark newInstance(CoachMarkBuilder builder) {
+ return FragmentBundlerCompat.create(new PopUpCoachMark())
+ .put(ARG_POP_UP_COACH_MARK_BUILDER_PARCEL, builder)
+ .build();
+ }
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ Dialog dialog = super.onCreateDialog(savedInstanceState);
+ Window window = dialog.getWindow();
+ if (window == null) {
+ Log.wtf(TAG, "getWindow() should not be null ever");
+ return dialog;
+ }
+ window.getAttributes().windowAnimations = R.style.coach_mark_dialog_animation;
+ window.setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(getContext(),
+ R.color.coach_mark_transparent_color)));
+ dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
+ return dialog;
+ }
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setStyle(STYLE_NO_FRAME, R.style.AppTheme);
+
+ final Context context = getContext();
+ final IStringResourceProvider stringResourceProvider = new DefaultStringResourceProvider(context);
+ final IDimensionResourceProvider dimensionResourceProvider = new DefaultDimensionResourceProvider(context);
+ final ITypeFaceProvider typeFaceProvider = new DefaultTypeFaceProvider(context);
+ final IScreenInfoProvider screenInfoProvider = new DefaultScreenInfoProvider(context);
+
+ mPopUpCoachMarkPresenter = new PopUpCoachMarkPresenter(stringResourceProvider, dimensionResourceProvider,
+ typeFaceProvider, screenInfoProvider);
+ //coach mark bundle is injected in onCreate as its available from bundle only
+ //If we decide to migrate to DI pattern this will be useful
+ mPopUpCoachMarkPresenter.onCreate(getCoachMarkBuilderFromBundle());
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ super.onCreateView(inflater, container, savedInstanceState);
+ final View view = inflater.inflate(R.layout.pop_up_coach_mark, container, false);
+ mViews = new Views(view);
+ mPopUpCoachMarkPresenter.onCreateView(this);
+ registerClickListener();
+ return view;
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ mPopUpCoachMarkPresenter.onViewCreated();
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ unRegisterClickListener();
+ mViews = null;
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ mPopUpCoachMarkPresenter.onDestroy();
+ mPopUpCoachMarkPresenter = null;
+ }
+
+ //region presentation methods
+ @Override
+ public void createViewToBeMaskedOut(int startX, int startY, int height, int width) {
+ View view = new View(getContext());
+ FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(width, height);
+ layoutParams.setMargins(startX, startY, NO_MARGIN, NO_MARGIN);
+ view.setLayoutParams(layoutParams);
+ view.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.coach_mark_black_translucent));
+ mViews.rlShimOutViewParent.addView(view);
+ }
+
+ @Override
+ public void dismissWithError(String message) {
+ Toast.makeText(getContext(), message, Toast.LENGTH_LONG).show();
+ mViews.rlCoachMarkParent.setVisibility(View.INVISIBLE);
+ }
+
+ @Override
+ public void onDismiss() {
+ dismiss();
+ }
+
+ @Override
+ public void setImageInformation(double centerX, double centerY, int imageWidth, int imageHeight, int backGroundTint, int imageDrawableRes) {
+ RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(imageWidth, imageHeight);
+ layoutParams.setMargins((int) (centerX - (imageWidth / 2)), (int) (centerY - (imageHeight / 2)), NO_MARGIN, NO_MARGIN);
+ mViews.ivCoachMarkImage.setLayoutParams(layoutParams);
+ mViews.ivCoachMarkImage.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.coach_mark_transparent_color));
+ mViews.ivCoachMarkImage.setImageDrawable(ContextCompat.getDrawable(getContext(), imageDrawableRes));
+ mViews.ivCoachMarkImage.setColorFilter(ContextCompat.getColor(getContext(), backGroundTint));
+ }
+
+ @Override
+ public void setPopUpViewPositionWithRespectToImage(@CoachMarkAlignPosition int alignPosition) {
+ RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) mViews.llPopUpCoachMarkParent.getLayoutParams();
+ layoutParams.addRule(alignPosition, mViews.ivCoachMarkImage.getId());
+ mViews.llPopUpCoachMarkParent.setLayoutParams(layoutParams);
+ }
+
+ @Override
+ public void setPopUpViewTopLeft(Rect margin, @CoachMarkLayoutOrientation int orientation) {
+ RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) mViews.llPopUpCoachMarkParent.getLayoutParams();
+ layoutParams.setMargins(margin.left, margin.top, margin.right, margin.bottom);
+ mViews.llPopUpCoachMarkParent.setLayoutParams(layoutParams);
+ mViews.llPopUpCoachMarkParent.setOrientation(orientation);
+ mViews.vRightBottomNotch.setVisibility(View.VISIBLE);
+ mViews.vLeftTopNotch.setVisibility(View.GONE);
+ }
+
+ @Override
+ public void setPopUpViewBottomRight(Rect margin, @CoachMarkLayoutOrientation int orientation) {
+ RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) mViews.llPopUpCoachMarkParent.getLayoutParams();
+ layoutParams.setMargins(margin.left, margin.top, margin.right, margin.bottom);
+ mViews.llPopUpCoachMarkParent.setLayoutParams(layoutParams);
+ mViews.llPopUpCoachMarkParent.setOrientation(orientation);
+ mViews.vRightBottomNotch.setVisibility(View.GONE);
+ mViews.vLeftTopNotch.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ public void setDismissButtonPositionLeft() {
+ RelativeLayout.LayoutParams okButtonLayoutParams = (RelativeLayout.LayoutParams) mViews.tvPopUpDismissButton.getLayoutParams();
+ RelativeLayout.LayoutParams separatorLayoutParams = (RelativeLayout.LayoutParams) mViews.vSeparator.getLayoutParams();
+ RelativeLayout.LayoutParams coachMarkTextParams = (RelativeLayout.LayoutParams) mViews.test.getLayoutParams();
+ okButtonLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, mViews.rlCoachMarkTextPart.getId());
+ mViews.tvPopUpDismissButton.setLayoutParams(okButtonLayoutParams);
+ separatorLayoutParams.addRule(RelativeLayout.RIGHT_OF, mViews.tvPopUpDismissButton.getId());
+ mViews.vSeparator.setLayoutParams(separatorLayoutParams);
+ coachMarkTextParams.addRule(RelativeLayout.RIGHT_OF, mViews.vSeparator.getId());
+ mViews.test.setLayoutParams(coachMarkTextParams);
+ }
+
+ @Override
+ public void setDismissButtonPositionRight() {
+ RelativeLayout.LayoutParams okButtonLayoutParams = (RelativeLayout.LayoutParams) mViews.tvPopUpDismissButton.getLayoutParams();
+ RelativeLayout.LayoutParams separatorLayoutParams = (RelativeLayout.LayoutParams) mViews.vSeparator.getLayoutParams();
+ RelativeLayout.LayoutParams coachMarkTextParams = (RelativeLayout.LayoutParams) mViews.test.getLayoutParams();
+ coachMarkTextParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, mViews.rlCoachMarkTextPart.getId());
+ mViews.test.setLayoutParams(coachMarkTextParams);
+ separatorLayoutParams.addRule(RelativeLayout.RIGHT_OF, mViews.test.getId());
+ mViews.vSeparator.setLayoutParams(separatorLayoutParams);
+ okButtonLayoutParams.addRule(RelativeLayout.RIGHT_OF, mViews.vSeparator.getId());
+ mViews.tvPopUpDismissButton.setLayoutParams(okButtonLayoutParams);
+ }
+
+ @Override
+ public void startScaleAnimationOnImage() {
+ mViews.ivCoachMarkImage.startAnimation(TransitionUtils.createScaleAnimation());
+ }
+
+
+ @Override
+ public void startThrobAnimationOnImage() {
+ mViews.ivCoachMarkImage.startAnimation(TransitionUtils.createThrobAnimation());
+ }
+
+ @Override
+ public void startAlphaAnimationOnImage() {
+ mViews.ivCoachMarkImage.startAnimation(TransitionUtils.createAlphaAnimation());
+ }
+
+ @Override
+ public void setNotchPositionIfPopUpTopLeft(Rect margin, float rotation) {
+ mViews.vRightBottomNotch.setRotation(rotation);
+ LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) mViews.vRightBottomNotch.getLayoutParams();
+ layoutParams.setMargins(margin.left, margin.top, margin.right, margin.bottom);
+ mViews.vRightBottomNotch.setLayoutParams(layoutParams);
+ }
+
+ @Override
+ public void setNotchPositionIfPopUpBottomRight(Rect margin, float rotation) {
+ mViews.vLeftTopNotch.setRotation(rotation);
+ LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) mViews.vLeftTopNotch.getLayoutParams();
+ layoutParams.setMargins(margin.left, margin.top, margin.right, margin.bottom);
+ mViews.vLeftTopNotch.setLayoutParams(layoutParams);
+ }
+
+ @Override
+ public void setTypeFaceForDismissButton(Typeface typeface) {
+ mViews.tvPopUpDismissButton.setTypeface(typeface);
+ }
+
+ @Override
+ public void setTypeFaceForPopUpText(Typeface typeface) {
+ mViews.tvPopUpCoachMarkText.setTypeface(typeface);
+ }
+
+ @Override
+ public void setUpGravityForCoachMarkText(@CoachMarkTextGravity int gravity) {
+ mViews.tvPopUpCoachMarkText.setGravity(gravity);
+ }
+
+ @Override
+ public void uiAdjustmentForNotchIfPopUpRight(Rect margin) {
+ ViewUtils.setToVisible(mViews.vNotchBaseWhiteLeft);
+ RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) mViews.vNotchBaseWhiteLeft.getLayoutParams();
+ layoutParams.setMargins(margin.left, margin.top, margin.right, margin.bottom);
+ mViews.vNotchBaseWhiteLeft.setLayoutParams(layoutParams);
+ }
+
+ @Override
+ public void uiAdjustmentForNotchIfPopUpBottom(Rect margin) {
+ ViewUtils.setToVisible(mViews.vNotchBaseWhiteTop);
+ RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) mViews.vNotchBaseWhiteTop.getLayoutParams();
+ layoutParams.setMargins(margin.left, margin.top, margin.right, margin.bottom);
+ mViews.vNotchBaseWhiteTop.setLayoutParams(layoutParams);
+ }
+
+ @Override
+ public void setCoachMarkMessage(String message) {
+ mViews.tvPopUpCoachMarkText.setText(message);
+ }
+
+ //endregion
+
+ //region click listeners
+ @Override
+ public void onClick(View v) {
+ if (v.getId() == R.id.tv_ok_button) {
+ if (mPopUpCoachMarkPresenter != null) {
+ mPopUpCoachMarkPresenter.onOkButtonClicked();
+ }
+ } else if (v.getId() == R.id.rl_shim_out_view_parent) {
+ mPopUpCoachMarkPresenter.onShimClicked();
+ }
+ }
+ //endregion
+
+ //region helper methods
+ private CoachMarkBuilder getCoachMarkBuilderFromBundle() {
+ return getArguments().getParcelable(ARG_POP_UP_COACH_MARK_BUILDER_PARCEL);
+ }
+
+ private void registerClickListener() {
+ mViews.tvPopUpDismissButton.setOnClickListener(this);
+ mViews.rlShimOutViewParent.setOnClickListener(this);
+ }
+
+ private void unRegisterClickListener() {
+ mViews.tvPopUpDismissButton.setOnClickListener(null);
+ mViews.rlShimOutViewParent.setOnClickListener(null);
+ }
+ //endregion
+
+}
diff --git a/coachmarks/src/main/java/com/myntra/coachmarks/builder/CoachMarkBuilder.java b/coachmarks/src/main/java/com/myntra/coachmarks/builder/CoachMarkBuilder.java
new file mode 100644
index 0000000..fb21551
--- /dev/null
+++ b/coachmarks/src/main/java/com/myntra/coachmarks/builder/CoachMarkBuilder.java
@@ -0,0 +1,137 @@
+package com.myntra.coachmarks.builder;
+
+import android.graphics.Point;
+import android.os.Parcelable;
+import android.support.annotation.ColorRes;
+import android.support.annotation.DimenRes;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.Nullable;
+import android.support.annotation.StringRes;
+
+import com.google.auto.value.AutoValue;
+import com.myntra.coachmarks.R;
+import com.myntra.coachmarks.common.AnimationType;
+import com.myntra.coachmarks.common.CoachMarkTextGravity;
+import com.myntra.coachmarks.common.DialogDismissButtonPosition;
+import com.myntra.coachmarks.common.PopUpPosition;
+
+import java.util.ArrayList;
+
+@AutoValue
+public abstract class CoachMarkBuilder implements Parcelable {
+
+ public static Builder create(Point coachMarkViewAnchorTop,
+ Point coachMarkViewAnchorBottom,
+ @StringRes int coachMarkMessage) {
+ double DEFAULT_NOTCH_POSITION = 0.0;
+ return new AutoValue_CoachMarkBuilder.Builder()
+ .setAnchorTop(coachMarkViewAnchorTop)
+ .setAnchorBottom(coachMarkViewAnchorBottom)
+ .setCoachMarkMessage(coachMarkMessage)
+ .setCoachMarkTextGravity(CoachMarkTextGravity.LEFT)
+ .setActionBarHeight(R.dimen.coach_mark_zero_dp)
+ .setFooterHeight(R.dimen.coach_mark_zero_dp)
+ .setInfoForViewToMaskList(new ArrayList(0))
+ .setAnimationTypeOnImage(AnimationType.THROB_ANIMATION)
+ .setUserDesiredPopUpPositionWithRespectToView(PopUpPosition.RIGHT)
+ .setBackGroundTintForImage(R.color.coach_mark_transparent_color)
+ .setImageDrawableRes(R.drawable.coachmark_drawable_no_image)
+ .setNotchPosition(DEFAULT_NOTCH_POSITION)
+ .setCoachMarkLayoutMargin(CoachMarkLayoutMargin.create().build())
+ .setImageLayoutInformation(ImageLayoutInformation.create(R.dimen.coach_mark_zero_dp, R.dimen.coach_mark_zero_dp).build())
+ .setFontStyleForDismissButton(null)
+ .setFontStyleForCoachMarkText(null);
+ }
+
+ @SuppressWarnings("unused")
+ public Builder newBuilder() {
+ return new AutoValue_CoachMarkBuilder.Builder(this);
+ }
+
+ public abstract Point getAnchorTop();
+
+ public abstract Point getAnchorBottom();
+
+ @StringRes
+ public abstract int getCoachMarkMessage();
+
+ @DimenRes
+ public abstract int getActionBarHeight();
+
+ @DimenRes
+ public abstract int getFooterHeight();
+
+ @Nullable
+ public abstract ArrayList getInfoForViewToMaskList();
+
+ @AnimationType
+ public abstract int getAnimationTypeOnImage();
+
+ @CoachMarkTextGravity
+ public abstract int getCoachMarkTextGravity();
+
+ @Nullable
+ public abstract String getFontStyleForDismissButton();
+
+ @Nullable
+ public abstract String getFontStyleForCoachMarkText();
+
+ @DialogDismissButtonPosition
+ public abstract int getPopUpCoachMarkDismissButtonPosition();
+
+ public abstract double getNotchPosition();
+
+ @PopUpPosition
+ public abstract int getUserDesiredPopUpPositionWithRespectToView();
+
+ @ColorRes
+ public abstract int getBackGroundTintForImage();
+
+ @DrawableRes
+ public abstract int getImageDrawableRes();
+
+ public abstract CoachMarkLayoutMargin getCoachMarkLayoutMargin();
+
+ public abstract ImageLayoutInformation getImageLayoutInformation();
+
+ @AutoValue.Builder
+ public static abstract class Builder {
+
+ public abstract Builder setAnchorTop(Point anchorTop);
+
+ public abstract Builder setAnchorBottom(Point anchorBottom);
+
+ public abstract Builder setCoachMarkMessage(@StringRes int coachMarkMessage);
+
+ public abstract Builder setCoachMarkTextGravity(@CoachMarkTextGravity int coachMarkTextGravity);
+
+ public abstract Builder setFontStyleForDismissButton(@Nullable String fontStyleForDismissButton);
+
+ public abstract Builder setFontStyleForCoachMarkText(@Nullable String fontStyleForCoachMarkText);
+
+ public abstract Builder setActionBarHeight(@DimenRes int actionBarHeight);
+
+ public abstract Builder setFooterHeight(@DimenRes int footerHeight);
+
+ public abstract Builder setInfoForViewToMaskList(@Nullable ArrayList infoForViewToMaskList);
+
+ public abstract Builder setAnimationTypeOnImage(@AnimationType int animationTypeOnImage);
+
+ public abstract Builder setPopUpCoachMarkDismissButtonPosition(@DialogDismissButtonPosition int popUpCoachMarkDismissButtonPosition);
+
+ public abstract Builder setNotchPosition(double notchPosition);
+
+ public abstract Builder setUserDesiredPopUpPositionWithRespectToView(@PopUpPosition int userDesiredPopUpPositionWithRespectToView);
+
+ public abstract Builder setBackGroundTintForImage(@ColorRes int backGroundTintForImage);
+
+ public abstract Builder setImageDrawableRes(@DrawableRes int imageDrawableRes);
+
+ public abstract Builder setCoachMarkLayoutMargin(CoachMarkLayoutMargin coachMarkLayoutMargin);
+
+ public abstract Builder setImageLayoutInformation(ImageLayoutInformation imageLayoutInformation);
+
+ public abstract CoachMarkBuilder build();
+
+ }
+}
diff --git a/coachmarks/src/main/java/com/myntra/coachmarks/builder/CoachMarkLayoutMargin.java b/coachmarks/src/main/java/com/myntra/coachmarks/builder/CoachMarkLayoutMargin.java
new file mode 100644
index 0000000..9ffb23d
--- /dev/null
+++ b/coachmarks/src/main/java/com/myntra/coachmarks/builder/CoachMarkLayoutMargin.java
@@ -0,0 +1,46 @@
+package com.myntra.coachmarks.builder;
+
+import android.os.Parcelable;
+import android.support.annotation.DimenRes;
+
+import com.google.auto.value.AutoValue;
+import com.myntra.coachmarks.R;
+
+@AutoValue
+public abstract class CoachMarkLayoutMargin implements Parcelable {
+
+ public static CoachMarkLayoutMargin.Builder create() {
+ return new AutoValue_CoachMarkLayoutMargin.Builder()
+ .setLeftMarginForCoachMark(R.dimen.coach_mark_zero_dp)
+ .setRightMarginForCoachMark(R.dimen.coach_mark_zero_dp)
+ .setTopMarginForCoachMark(R.dimen.coach_mark_zero_dp)
+ .setBottomMarginForCoachMark(R.dimen.coach_mark_zero_dp);
+ }
+
+ @DimenRes
+ public abstract int getLeftMarginForCoachMark();
+
+ @DimenRes
+ public abstract int getRightMarginForCoachMark();
+
+ @DimenRes
+ public abstract int getTopMarginForCoachMark();
+
+ @DimenRes
+ public abstract int getBottomMarginForCoachMark();
+
+ @AutoValue.Builder
+ public static abstract class Builder {
+
+ public abstract Builder setLeftMarginForCoachMark(@DimenRes int leftMarginForView);
+
+ public abstract Builder setRightMarginForCoachMark(@DimenRes int rightMarginForView);
+
+ public abstract Builder setTopMarginForCoachMark(@DimenRes int topMarginForView);
+
+ public abstract Builder setBottomMarginForCoachMark(@DimenRes int bottomMarginForView);
+
+ public abstract CoachMarkLayoutMargin build();
+
+ }
+}
diff --git a/coachmarks/src/main/java/com/myntra/coachmarks/builder/CoachMarkPixelInfo.java b/coachmarks/src/main/java/com/myntra/coachmarks/builder/CoachMarkPixelInfo.java
new file mode 100644
index 0000000..136920a
--- /dev/null
+++ b/coachmarks/src/main/java/com/myntra/coachmarks/builder/CoachMarkPixelInfo.java
@@ -0,0 +1,92 @@
+package com.myntra.coachmarks.builder;
+
+import android.graphics.Rect;
+import android.os.Parcelable;
+
+import com.google.auto.value.AutoValue;
+
+@AutoValue
+public abstract class CoachMarkPixelInfo implements Parcelable {
+
+ public static CoachMarkPixelInfo.Builder create() {
+ return new AutoValue_CoachMarkPixelInfo.Builder()
+ .setImageWidthInPixels(0)
+ .setImageHeightInPixels(0)
+ .setMarginRectInPixels(new Rect(0, 0, 0, 0))
+ .setPopUpWidthInPixelsWithOffset(0)
+ .setPopUpHeightInPixelsWithOffset(0)
+ .setPopUpWidthInPixels(0)
+ .setPopUpHeightInPixels(0)
+ .setScreenWidthInPixels(0)
+ .setScreenHeightInPixels(0)
+ .setNotchDimenInPixels(0)
+ .setActionBarHeightPixels(0)
+ .setFooterHeightPixels(0)
+ .setMarginOffsetForNotchInPixels(0)
+ .setWidthHeightOffsetForCoachMarkPopUp(0);
+ }
+
+ public abstract int getImageWidthInPixels();
+
+ public abstract int getImageHeightInPixels();
+
+ public abstract Rect getMarginRectInPixels();
+
+ public abstract int getPopUpWidthInPixelsWithOffset();
+
+ public abstract int getPopUpHeightInPixelsWithOffset();
+
+ public abstract int getPopUpWidthInPixels();
+
+ public abstract int getPopUpHeightInPixels();
+
+ public abstract int getScreenWidthInPixels();
+
+ public abstract int getScreenHeightInPixels();
+
+ public abstract int getNotchDimenInPixels();
+
+ public abstract int getActionBarHeightPixels();
+
+ public abstract int getFooterHeightPixels();
+
+ public abstract int getMarginOffsetForNotchInPixels();
+
+ public abstract int getWidthHeightOffsetForCoachMarkPopUp();
+
+
+ @AutoValue.Builder
+ public static abstract class Builder {
+
+ public abstract Builder setImageWidthInPixels(int imageWidthInPixels);
+
+ public abstract Builder setImageHeightInPixels(int imageHeightInPixels);
+
+ public abstract Builder setMarginRectInPixels(Rect coachMarkMarginRectInPixels);
+
+ public abstract Builder setPopUpWidthInPixelsWithOffset(int coachMarkPopUpWidthInPixelsWithOffset);
+
+ public abstract Builder setPopUpHeightInPixelsWithOffset(int coachMarkPopUpHeightInPixelsWithOffset);
+
+ public abstract Builder setPopUpWidthInPixels(int coachMarkPopUpWidthInPixels);
+
+ public abstract Builder setPopUpHeightInPixels(int coachMarkPopUpHeightInPixels);
+
+ public abstract Builder setScreenWidthInPixels(int screenWidthInPixels);
+
+ public abstract Builder setScreenHeightInPixels(int screenHeightInPixels);
+
+ public abstract Builder setNotchDimenInPixels(int notchDimenInPixels);
+
+ public abstract Builder setActionBarHeightPixels(int actionBarHeightPixels);
+
+ public abstract Builder setFooterHeightPixels(int footerHeightPixels);
+
+ public abstract Builder setMarginOffsetForNotchInPixels(int marginOffsetForNotchInPixels);
+
+ public abstract Builder setWidthHeightOffsetForCoachMarkPopUp(int widthHeightOffsetForCoachMarkPopUp);
+
+ public abstract CoachMarkPixelInfo build();
+
+ }
+}
diff --git a/coachmarks/src/main/java/com/myntra/coachmarks/builder/ImageLayoutInformation.java b/coachmarks/src/main/java/com/myntra/coachmarks/builder/ImageLayoutInformation.java
new file mode 100644
index 0000000..b37fd94
--- /dev/null
+++ b/coachmarks/src/main/java/com/myntra/coachmarks/builder/ImageLayoutInformation.java
@@ -0,0 +1,34 @@
+package com.myntra.coachmarks.builder;
+
+import android.os.Parcelable;
+import android.support.annotation.DimenRes;
+
+import com.google.auto.value.AutoValue;
+
+@AutoValue
+public abstract class ImageLayoutInformation implements Parcelable {
+
+ public static Builder create(@DimenRes int imageWidth, @DimenRes int imageHeight) {
+ return new AutoValue_ImageLayoutInformation.Builder()
+ .setImageWidth(imageWidth)
+ .setImageHeight(imageHeight);
+
+ }
+
+ @DimenRes
+ public abstract int getImageHeight();
+
+ @DimenRes
+ public abstract int getImageWidth();
+
+ @AutoValue.Builder
+ public static abstract class Builder {
+
+ public abstract Builder setImageHeight(@DimenRes int imageHeight);
+
+ public abstract Builder setImageWidth(@DimenRes int imageWidth);
+
+ public abstract ImageLayoutInformation build();
+
+ }
+}
diff --git a/coachmarks/src/main/java/com/myntra/coachmarks/builder/InfoForViewToMask.java b/coachmarks/src/main/java/com/myntra/coachmarks/builder/InfoForViewToMask.java
new file mode 100644
index 0000000..b871f97
--- /dev/null
+++ b/coachmarks/src/main/java/com/myntra/coachmarks/builder/InfoForViewToMask.java
@@ -0,0 +1,37 @@
+package com.myntra.coachmarks.builder;
+
+import android.graphics.Point;
+import android.os.Parcelable;
+
+import com.google.auto.value.AutoValue;
+
+@AutoValue
+public abstract class InfoForViewToMask implements Parcelable {
+
+ public static Builder create(Point viewToMaskStartPosition, int viewToMaskHeight, int viewToMaskWidth) {
+ return new AutoValue_InfoForViewToMask.Builder()
+ .setViewToMaskStartPosition(viewToMaskStartPosition)
+ .setViewToMaskHeight(viewToMaskHeight)
+ .setViewToMaskWidth(viewToMaskWidth);
+ }
+
+ public abstract Point getViewToMaskStartPosition();
+
+ public abstract int getViewToMaskHeight();
+
+ public abstract int getViewToMaskWidth();
+
+ @AutoValue.Builder
+ public static abstract class Builder {
+
+ public abstract Builder setViewToMaskStartPosition(Point viewToMaskStartPosition);
+
+ public abstract Builder setViewToMaskHeight(int viewToMaskHeight);
+
+ public abstract Builder setViewToMaskWidth(int viewToMaskWidth);
+
+ public abstract InfoForViewToMask build();
+
+ }
+
+}
diff --git a/coachmarks/src/main/java/com/myntra/coachmarks/common/AnimationType.java b/coachmarks/src/main/java/com/myntra/coachmarks/common/AnimationType.java
new file mode 100644
index 0000000..3146f49
--- /dev/null
+++ b/coachmarks/src/main/java/com/myntra/coachmarks/common/AnimationType.java
@@ -0,0 +1,18 @@
+package com.myntra.coachmarks.common;
+
+import android.support.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@IntDef({AnimationType.THROB_ANIMATION,
+ AnimationType.SCALE_ANIMATION,
+ AnimationType.ALPHA_ANIMATION,
+ AnimationType.ANIMATION_NONE})
+@Retention(RetentionPolicy.SOURCE)
+public @interface AnimationType {
+ int THROB_ANIMATION = 0;
+ int SCALE_ANIMATION = 1;
+ int ALPHA_ANIMATION = 2;
+ int ANIMATION_NONE = 3;
+}
\ No newline at end of file
diff --git a/coachmarks/src/main/java/com/myntra/coachmarks/common/CoachMarkAlignPosition.java b/coachmarks/src/main/java/com/myntra/coachmarks/common/CoachMarkAlignPosition.java
new file mode 100644
index 0000000..7e8f711
--- /dev/null
+++ b/coachmarks/src/main/java/com/myntra/coachmarks/common/CoachMarkAlignPosition.java
@@ -0,0 +1,19 @@
+package com.myntra.coachmarks.common;
+
+import android.support.annotation.IntDef;
+import android.widget.RelativeLayout;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@IntDef({CoachMarkAlignPosition.ALIGN_LEFT,
+ CoachMarkAlignPosition.ALIGN_TOP,
+ CoachMarkAlignPosition.ALIGN_RIGHT,
+ CoachMarkAlignPosition.ALIGN_BOTTOM})
+@Retention(RetentionPolicy.SOURCE)
+public @interface CoachMarkAlignPosition {
+ int ALIGN_LEFT = RelativeLayout.ALIGN_LEFT;
+ int ALIGN_TOP = RelativeLayout.ALIGN_TOP;
+ int ALIGN_RIGHT = RelativeLayout.ALIGN_RIGHT;
+ int ALIGN_BOTTOM = RelativeLayout.ALIGN_BOTTOM;
+}
\ No newline at end of file
diff --git a/coachmarks/src/main/java/com/myntra/coachmarks/common/CoachMarkLayoutOrientation.java b/coachmarks/src/main/java/com/myntra/coachmarks/common/CoachMarkLayoutOrientation.java
new file mode 100644
index 0000000..2caae34
--- /dev/null
+++ b/coachmarks/src/main/java/com/myntra/coachmarks/common/CoachMarkLayoutOrientation.java
@@ -0,0 +1,14 @@
+package com.myntra.coachmarks.common;
+
+import android.support.annotation.IntDef;
+import android.widget.LinearLayout;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@IntDef({CoachMarkLayoutOrientation.HORIZONTAL, CoachMarkLayoutOrientation.VERTICAL})
+@Retention(RetentionPolicy.SOURCE)
+public @interface CoachMarkLayoutOrientation {
+ int HORIZONTAL = LinearLayout.HORIZONTAL;
+ int VERTICAL = LinearLayout.VERTICAL;
+}
\ No newline at end of file
diff --git a/coachmarks/src/main/java/com/myntra/coachmarks/common/CoachMarkTextGravity.java b/coachmarks/src/main/java/com/myntra/coachmarks/common/CoachMarkTextGravity.java
new file mode 100644
index 0000000..13e641c
--- /dev/null
+++ b/coachmarks/src/main/java/com/myntra/coachmarks/common/CoachMarkTextGravity.java
@@ -0,0 +1,17 @@
+package com.myntra.coachmarks.common;
+
+import android.support.annotation.IntDef;
+import android.view.Gravity;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@IntDef({CoachMarkTextGravity.LEFT,
+ CoachMarkTextGravity.CENTER,
+ CoachMarkTextGravity.RIGHT})
+@Retention(RetentionPolicy.SOURCE)
+public @interface CoachMarkTextGravity {
+ int LEFT = Gravity.LEFT;
+ int CENTER = Gravity.CENTER;
+ int RIGHT = Gravity.RIGHT;
+}
\ No newline at end of file
diff --git a/coachmarks/src/main/java/com/myntra/coachmarks/common/DialogDismissButtonPosition.java b/coachmarks/src/main/java/com/myntra/coachmarks/common/DialogDismissButtonPosition.java
new file mode 100644
index 0000000..3ed6818
--- /dev/null
+++ b/coachmarks/src/main/java/com/myntra/coachmarks/common/DialogDismissButtonPosition.java
@@ -0,0 +1,14 @@
+package com.myntra.coachmarks.common;
+
+import android.support.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@IntDef({DialogDismissButtonPosition.LEFT,
+ DialogDismissButtonPosition.RIGHT})
+@Retention(RetentionPolicy.SOURCE)
+public @interface DialogDismissButtonPosition {
+ int LEFT = 0;
+ int RIGHT = 1;
+}
\ No newline at end of file
diff --git a/coachmarks/src/main/java/com/myntra/coachmarks/common/PopUpPosition.java b/coachmarks/src/main/java/com/myntra/coachmarks/common/PopUpPosition.java
new file mode 100644
index 0000000..42b72af
--- /dev/null
+++ b/coachmarks/src/main/java/com/myntra/coachmarks/common/PopUpPosition.java
@@ -0,0 +1,20 @@
+package com.myntra.coachmarks.common;
+
+import android.support.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@IntDef({PopUpPosition.LEFT,
+ PopUpPosition.RIGHT,
+ PopUpPosition.BOTTOM,
+ PopUpPosition.TOP,
+ PopUpPosition.NONE})
+@Retention(RetentionPolicy.SOURCE)
+public @interface PopUpPosition {
+ int LEFT = 0;
+ int RIGHT = 1;
+ int TOP = 2;
+ int BOTTOM = 3;
+ int NONE = 4;
+}
\ No newline at end of file
diff --git a/coachmarks/src/main/java/com/myntra/coachmarks/providers/DefaultDimensionResourceProvider.java b/coachmarks/src/main/java/com/myntra/coachmarks/providers/DefaultDimensionResourceProvider.java
new file mode 100644
index 0000000..7b7f91d
--- /dev/null
+++ b/coachmarks/src/main/java/com/myntra/coachmarks/providers/DefaultDimensionResourceProvider.java
@@ -0,0 +1,23 @@
+package com.myntra.coachmarks.providers;
+
+import android.content.Context;
+import android.support.annotation.DimenRes;
+
+import com.myntra.coachmarks.providers.interfaces.IDimensionResourceProvider;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
+@ParametersAreNonnullByDefault
+public class DefaultDimensionResourceProvider implements IDimensionResourceProvider {
+
+ private Context mContext;
+
+ public DefaultDimensionResourceProvider(final Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public int getDimensionInPixel(@DimenRes final int dimenRes) {
+ return mContext.getResources().getDimensionPixelSize(dimenRes);
+ }
+}
diff --git a/coachmarks/src/main/java/com/myntra/coachmarks/providers/DefaultScreenInfoProvider.java b/coachmarks/src/main/java/com/myntra/coachmarks/providers/DefaultScreenInfoProvider.java
new file mode 100644
index 0000000..681b84e
--- /dev/null
+++ b/coachmarks/src/main/java/com/myntra/coachmarks/providers/DefaultScreenInfoProvider.java
@@ -0,0 +1,30 @@
+package com.myntra.coachmarks.providers;
+
+import android.content.Context;
+import android.util.DisplayMetrics;
+
+import com.myntra.coachmarks.providers.interfaces.IScreenInfoProvider;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
+@ParametersAreNonnullByDefault
+public class DefaultScreenInfoProvider implements IScreenInfoProvider {
+
+ private Context mContext;
+
+ public DefaultScreenInfoProvider(final Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public int getScreenHeightInPixels() {
+ DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
+ return displayMetrics.heightPixels;
+ }
+
+ @Override
+ public int getScreenWidthInPixels() {
+ DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
+ return displayMetrics.widthPixels;
+ }
+}
diff --git a/coachmarks/src/main/java/com/myntra/coachmarks/providers/DefaultStringResourceProvider.java b/coachmarks/src/main/java/com/myntra/coachmarks/providers/DefaultStringResourceProvider.java
new file mode 100644
index 0000000..9c2b199
--- /dev/null
+++ b/coachmarks/src/main/java/com/myntra/coachmarks/providers/DefaultStringResourceProvider.java
@@ -0,0 +1,28 @@
+package com.myntra.coachmarks.providers;
+
+import android.content.Context;
+import android.support.annotation.StringRes;
+
+import com.myntra.coachmarks.providers.interfaces.IStringResourceProvider;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
+@ParametersAreNonnullByDefault
+public class DefaultStringResourceProvider implements IStringResourceProvider {
+
+ private Context mContext;
+
+ public DefaultStringResourceProvider(final Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public String getStringFromResource(@StringRes final int stringRes) {
+ return mContext.getString(stringRes);
+ }
+
+ @Override
+ public String getStringFromResource(@StringRes final int stringResId, final Object... formatArgs) {
+ return mContext.getString(stringResId, formatArgs);
+ }
+}
diff --git a/coachmarks/src/main/java/com/myntra/coachmarks/providers/DefaultTypeFaceProvider.java b/coachmarks/src/main/java/com/myntra/coachmarks/providers/DefaultTypeFaceProvider.java
new file mode 100644
index 0000000..b6199e7
--- /dev/null
+++ b/coachmarks/src/main/java/com/myntra/coachmarks/providers/DefaultTypeFaceProvider.java
@@ -0,0 +1,29 @@
+package com.myntra.coachmarks.providers;
+
+import android.content.Context;
+import android.graphics.Typeface;
+import android.util.Log;
+
+import com.myntra.coachmarks.providers.interfaces.ITypeFaceProvider;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
+@ParametersAreNonnullByDefault
+public class DefaultTypeFaceProvider implements ITypeFaceProvider {
+
+ private Context mContext;
+
+ public DefaultTypeFaceProvider(final Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public Typeface getTypeFaceFromAssets(final String fontFilePath) {
+ try {
+ return Typeface.createFromAsset(mContext.getAssets(), fontFilePath);
+ } catch (RuntimeException e) {
+ Log.e(DefaultTypeFaceProvider.class.getName(), e.getMessage());
+ }
+ return null;
+ }
+}
diff --git a/coachmarks/src/main/java/com/myntra/coachmarks/providers/interfaces/IDimensionResourceProvider.java b/coachmarks/src/main/java/com/myntra/coachmarks/providers/interfaces/IDimensionResourceProvider.java
new file mode 100644
index 0000000..ab952ca
--- /dev/null
+++ b/coachmarks/src/main/java/com/myntra/coachmarks/providers/interfaces/IDimensionResourceProvider.java
@@ -0,0 +1,7 @@
+package com.myntra.coachmarks.providers.interfaces;
+
+import android.support.annotation.DimenRes;
+
+public interface IDimensionResourceProvider {
+ int getDimensionInPixel(@DimenRes final int dimenRes);
+}
diff --git a/coachmarks/src/main/java/com/myntra/coachmarks/providers/interfaces/IScreenInfoProvider.java b/coachmarks/src/main/java/com/myntra/coachmarks/providers/interfaces/IScreenInfoProvider.java
new file mode 100644
index 0000000..d8bb2f7
--- /dev/null
+++ b/coachmarks/src/main/java/com/myntra/coachmarks/providers/interfaces/IScreenInfoProvider.java
@@ -0,0 +1,7 @@
+package com.myntra.coachmarks.providers.interfaces;
+
+public interface IScreenInfoProvider {
+ int getScreenHeightInPixels();
+
+ int getScreenWidthInPixels();
+}
diff --git a/coachmarks/src/main/java/com/myntra/coachmarks/providers/interfaces/IStringResourceProvider.java b/coachmarks/src/main/java/com/myntra/coachmarks/providers/interfaces/IStringResourceProvider.java
new file mode 100644
index 0000000..ad62317
--- /dev/null
+++ b/coachmarks/src/main/java/com/myntra/coachmarks/providers/interfaces/IStringResourceProvider.java
@@ -0,0 +1,12 @@
+package com.myntra.coachmarks.providers.interfaces;
+
+import android.support.annotation.StringRes;
+
+public interface IStringResourceProvider {
+
+ String getStringFromResource(@StringRes final int stringRes);
+
+ String getStringFromResource(@StringRes final int stringResId,
+ final Object... formatArgs);
+
+}
\ No newline at end of file
diff --git a/coachmarks/src/main/java/com/myntra/coachmarks/providers/interfaces/ITypeFaceProvider.java b/coachmarks/src/main/java/com/myntra/coachmarks/providers/interfaces/ITypeFaceProvider.java
new file mode 100644
index 0000000..d01fbad
--- /dev/null
+++ b/coachmarks/src/main/java/com/myntra/coachmarks/providers/interfaces/ITypeFaceProvider.java
@@ -0,0 +1,7 @@
+package com.myntra.coachmarks.providers.interfaces;
+
+import android.graphics.Typeface;
+
+public interface ITypeFaceProvider {
+ Typeface getTypeFaceFromAssets(final String fontFilePath);
+}
diff --git a/coachmarks/src/main/java/com/myntra/coachmarks/ui/common/BaseViews.java b/coachmarks/src/main/java/com/myntra/coachmarks/ui/common/BaseViews.java
new file mode 100644
index 0000000..a64f229
--- /dev/null
+++ b/coachmarks/src/main/java/com/myntra/coachmarks/ui/common/BaseViews.java
@@ -0,0 +1,26 @@
+package com.myntra.coachmarks.ui.common;
+
+import android.support.annotation.CallSuper;
+import android.view.View;
+
+import butterknife.ButterKnife;
+
+public abstract class BaseViews {
+
+ private View mRoot;
+
+ protected BaseViews(View root) {
+ mRoot = root;
+ ButterKnife.bind(this, root);
+ }
+
+ public View getRootView() {
+ return mRoot;
+ }
+
+ @CallSuper
+ public void clear() {
+ mRoot = null;
+ }
+
+}
diff --git a/coachmarks/src/main/java/com/myntra/coachmarks/ui/presentation/IPopUpCoachMarkPresentation.java b/coachmarks/src/main/java/com/myntra/coachmarks/ui/presentation/IPopUpCoachMarkPresentation.java
new file mode 100644
index 0000000..4b7bb45
--- /dev/null
+++ b/coachmarks/src/main/java/com/myntra/coachmarks/ui/presentation/IPopUpCoachMarkPresentation.java
@@ -0,0 +1,52 @@
+package com.myntra.coachmarks.ui.presentation;
+
+import android.graphics.Rect;
+import android.graphics.Typeface;
+
+import com.myntra.coachmarks.common.CoachMarkAlignPosition;
+import com.myntra.coachmarks.common.CoachMarkLayoutOrientation;
+import com.myntra.coachmarks.common.CoachMarkTextGravity;
+
+public interface IPopUpCoachMarkPresentation {
+ void createViewToBeMaskedOut(int startX, int startY, int height, int width);
+
+ void setImageInformation(double centerX, double centerY, int imageWidth,
+ int imageHeight, int backGroundTint, int imageDrawableRes);
+
+ void dismissWithError(String message);
+
+ void onDismiss();
+
+ void startThrobAnimationOnImage();
+
+ void setDismissButtonPositionLeft();
+
+ void setDismissButtonPositionRight();
+
+ void startScaleAnimationOnImage();
+
+ void startAlphaAnimationOnImage();
+
+ void setTypeFaceForDismissButton(Typeface typeface);
+
+ void setTypeFaceForPopUpText(Typeface typeface);
+
+ void setUpGravityForCoachMarkText(@CoachMarkTextGravity int gravity);
+
+ void setPopUpViewTopLeft(Rect margin, @CoachMarkLayoutOrientation int orientation);
+
+ void setPopUpViewBottomRight(Rect margin, @CoachMarkLayoutOrientation int orientation);
+
+ void setNotchPositionIfPopUpTopLeft(Rect margin, float rotation);
+
+ void setNotchPositionIfPopUpBottomRight(Rect margin, float rotation);
+
+ void uiAdjustmentForNotchIfPopUpRight(Rect margin);
+
+ void uiAdjustmentForNotchIfPopUpBottom(Rect margin);
+
+ void setCoachMarkMessage(String message);
+
+ void setPopUpViewPositionWithRespectToImage(@CoachMarkAlignPosition int alignPosition);
+
+}
diff --git a/coachmarks/src/main/java/com/myntra/coachmarks/ui/presenter/PopUpCoachMarkPresenter.java b/coachmarks/src/main/java/com/myntra/coachmarks/ui/presenter/PopUpCoachMarkPresenter.java
new file mode 100644
index 0000000..18208f2
--- /dev/null
+++ b/coachmarks/src/main/java/com/myntra/coachmarks/ui/presenter/PopUpCoachMarkPresenter.java
@@ -0,0 +1,450 @@
+package com.myntra.coachmarks.ui.presenter;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.Typeface;
+import android.support.annotation.ColorRes;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.Nullable;
+import android.support.annotation.StringRes;
+
+import com.myntra.coachmarks.R;
+import com.myntra.coachmarks.builder.CoachMarkBuilder;
+import com.myntra.coachmarks.builder.CoachMarkLayoutMargin;
+import com.myntra.coachmarks.builder.CoachMarkPixelInfo;
+import com.myntra.coachmarks.builder.InfoForViewToMask;
+import com.myntra.coachmarks.common.AnimationType;
+import com.myntra.coachmarks.common.CoachMarkAlignPosition;
+import com.myntra.coachmarks.common.CoachMarkLayoutOrientation;
+import com.myntra.coachmarks.common.CoachMarkTextGravity;
+import com.myntra.coachmarks.common.DialogDismissButtonPosition;
+import com.myntra.coachmarks.common.PopUpPosition;
+import com.myntra.coachmarks.providers.interfaces.IDimensionResourceProvider;
+import com.myntra.coachmarks.providers.interfaces.IScreenInfoProvider;
+import com.myntra.coachmarks.providers.interfaces.IStringResourceProvider;
+import com.myntra.coachmarks.providers.interfaces.ITypeFaceProvider;
+import com.myntra.coachmarks.ui.presentation.IPopUpCoachMarkPresentation;
+
+import java.util.List;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
+import zeta.android.utils.lang.StringUtils;
+
+@ParametersAreNonnullByDefault
+public class PopUpCoachMarkPresenter {
+
+ private static final double MAX_NOTCH_RANGE = .85;
+ private static final double MIN_NOTCH_RANGE = 0.0;
+
+ private static final int NO_MARGIN = 0;
+
+ private static final float ROTATION_0 = 0;
+ private static final float ROTATION_90 = 90;
+ private static final float ROTATION_180 = 180;
+ private static final float ROTATION_270 = 270;
+
+ private static final int MULTIPLICATION_FACTOR_FOR_NOTCH_UI_ADJUSTMENT = 3;
+
+ private CoachMarkBuilder mCoachMarkBuilder;
+ private IPopUpCoachMarkPresentation mPopUpCoachMarkPresentation;
+
+ private ITypeFaceProvider mTypeFaceProvider;
+ private IScreenInfoProvider mScreenInfoProvider;
+ private IStringResourceProvider mStringResourceProvider;
+ private IDimensionResourceProvider mDimensionResourceProvider;
+
+ public PopUpCoachMarkPresenter(final IStringResourceProvider stringResourceProvider,
+ final IDimensionResourceProvider dimensionResourceProvider,
+ final ITypeFaceProvider typeFaceProvider,
+ final IScreenInfoProvider screenInfoProvider) {
+ mStringResourceProvider = stringResourceProvider;
+ mDimensionResourceProvider = dimensionResourceProvider;
+ mTypeFaceProvider = typeFaceProvider;
+ mScreenInfoProvider = screenInfoProvider;
+ }
+
+ public void onCreate(CoachMarkBuilder coachMarkBuilder) {
+ mCoachMarkBuilder = coachMarkBuilder;
+ }
+
+ public void onCreateView(IPopUpCoachMarkPresentation popUpCoachMarkPresentation) {
+ mPopUpCoachMarkPresentation = popUpCoachMarkPresentation;
+ }
+
+ public void onViewCreated() {
+ displayCoachMark();
+ }
+
+ public void onDestroy() {
+ mPopUpCoachMarkPresentation = null;
+ mScreenInfoProvider = null;
+ mDimensionResourceProvider = null;
+ mStringResourceProvider = null;
+ mTypeFaceProvider = null;
+ }
+
+ public void onOkButtonClicked() {
+ if (mPopUpCoachMarkPresentation != null) {
+ mPopUpCoachMarkPresentation.onDismiss();
+ }
+ }
+
+ public void onShimClicked() {
+ if (mPopUpCoachMarkPresentation != null) {
+ mPopUpCoachMarkPresentation.onDismiss();
+ }
+ }
+
+ //region helper methods
+ private void displayCoachMark() {
+ CoachMarkPixelInfo coachMarkDimenInPixel = createCoachMarkPixelInfo();
+ @PopUpPosition
+ int popUpPosition = findCoachMarkTextPopUpDisplayPosition(mCoachMarkBuilder.getAnchorTop(),
+ mCoachMarkBuilder.getAnchorBottom(),
+ mCoachMarkBuilder.getUserDesiredPopUpPositionWithRespectToView(), coachMarkDimenInPixel);
+
+ if (popUpPosition == PopUpPosition.NONE) {
+ mPopUpCoachMarkPresentation.dismissWithError(
+ mStringResourceProvider.getStringFromResource(R.string.coachmark_no_position_found));
+ return;
+ }
+
+ setTypeFaceForDismissButton(mCoachMarkBuilder.getFontStyleForDismissButton());
+ setTypeFaceForCoachMarkText(mCoachMarkBuilder.getFontStyleForCoachMarkText());
+ setGravityForCoachMarkText(mCoachMarkBuilder.getCoachMarkTextGravity());
+ setMessageForCoachMarkText(mCoachMarkBuilder.getCoachMarkMessage());
+
+ setNotchDisplayEdge(popUpPosition, mCoachMarkBuilder.getAnchorTop().y, mCoachMarkBuilder.getAnchorBottom().y, mCoachMarkBuilder.getAnchorTop().x, coachMarkDimenInPixel);
+ detectAndCreateShimOutViews(mCoachMarkBuilder.getInfoForViewToMaskList());
+ setImageParamsAndPosition(mCoachMarkBuilder.getAnchorTop(), mCoachMarkBuilder.getAnchorBottom(), coachMarkDimenInPixel.getImageWidthInPixels(), coachMarkDimenInPixel.getImageHeightInPixels(), mCoachMarkBuilder.getBackGroundTintForImage(), mCoachMarkBuilder.getImageDrawableRes());
+ createAnimationOnImage(mCoachMarkBuilder.getAnimationTypeOnImage());
+ showCoachMark(mCoachMarkBuilder.getPopUpCoachMarkDismissButtonPosition(), popUpPosition);
+ }
+
+ private void setMessageForCoachMarkText(@StringRes int messageForCoachMarkTextRes) {
+ mPopUpCoachMarkPresentation.setCoachMarkMessage(mStringResourceProvider.getStringFromResource(messageForCoachMarkTextRes));
+ }
+
+ private void setTypeFaceForDismissButton(@Nullable String fontFileForDismissButton) {
+ if (StringUtils.isNotNullOrEmpty(fontFileForDismissButton)) {
+ Typeface typeface = mTypeFaceProvider.getTypeFaceFromAssets(fontFileForDismissButton);
+ if (typeface != null)
+ mPopUpCoachMarkPresentation.setTypeFaceForDismissButton(typeface);
+ }
+ }
+
+ private void setTypeFaceForCoachMarkText(@Nullable String fontFileForPopUpText) {
+ if (StringUtils.isNotNullOrEmpty(fontFileForPopUpText)) {
+ Typeface typeface = mTypeFaceProvider.getTypeFaceFromAssets(fontFileForPopUpText);
+ if (typeface != null)
+ mPopUpCoachMarkPresentation.setTypeFaceForPopUpText(typeface);
+ }
+ }
+
+ private void setGravityForCoachMarkText(int textAlignmentForPopUpText) {
+ switch (textAlignmentForPopUpText) {
+ case CoachMarkTextGravity.CENTER:
+ mPopUpCoachMarkPresentation.setUpGravityForCoachMarkText(CoachMarkTextGravity.CENTER);
+ break;
+ case CoachMarkTextGravity.LEFT:
+ mPopUpCoachMarkPresentation.setUpGravityForCoachMarkText(CoachMarkTextGravity.LEFT);
+ break;
+ case CoachMarkTextGravity.RIGHT:
+ mPopUpCoachMarkPresentation.setUpGravityForCoachMarkText(CoachMarkTextGravity.RIGHT);
+ break;
+ }
+ }
+
+ private void setNotchDisplayEdge(int position, int anchorTopY, int anchorBottomY, int anchorTopX, CoachMarkPixelInfo coachMarkDimenInPixel) {
+ int centerY = (anchorTopY + anchorBottomY) / 2;
+ int actualTopMargin;
+ int actualLeftMargin;
+ Rect coachMarkMarginRect;
+ int notchPosition;
+ Rect notchMarginRect;
+ Rect notchUiAdjustmentMarginRect;
+ switch (position) {
+ case PopUpPosition.LEFT:
+ actualTopMargin = getActualTopMargin(centerY, coachMarkDimenInPixel);
+ coachMarkMarginRect = new Rect(coachMarkDimenInPixel.getMarginRectInPixels().left, actualTopMargin - coachMarkDimenInPixel.getMarginRectInPixels().bottom, coachMarkDimenInPixel.getMarginRectInPixels().right + coachMarkDimenInPixel.getImageWidthInPixels(), NO_MARGIN);
+ mPopUpCoachMarkPresentation.setPopUpViewTopLeft(coachMarkMarginRect, CoachMarkLayoutOrientation.HORIZONTAL);
+ notchPosition = getMarginTopForNotch(mCoachMarkBuilder.getNotchPosition(), coachMarkDimenInPixel.getPopUpHeightInPixels(), coachMarkDimenInPixel.getNotchDimenInPixels());
+ notchMarginRect = new Rect(-coachMarkDimenInPixel.getMarginOffsetForNotchInPixels(), notchPosition, NO_MARGIN, NO_MARGIN);
+ mPopUpCoachMarkPresentation.setNotchPositionIfPopUpTopLeft(notchMarginRect, ROTATION_90);
+ break;
+ case PopUpPosition.TOP:
+ actualLeftMargin = getActualLeftMargin(anchorTopX, coachMarkDimenInPixel);
+ coachMarkMarginRect = new Rect(actualLeftMargin - coachMarkDimenInPixel.getMarginRectInPixels().right, coachMarkDimenInPixel.getMarginRectInPixels().top, NO_MARGIN, coachMarkDimenInPixel.getMarginRectInPixels().bottom + coachMarkDimenInPixel.getImageHeightInPixels());
+ mPopUpCoachMarkPresentation.setPopUpViewTopLeft(coachMarkMarginRect, CoachMarkLayoutOrientation.VERTICAL);
+ notchPosition = getMarginLeftForNotch(mCoachMarkBuilder.getNotchPosition(), coachMarkDimenInPixel.getPopUpWidthInPixels(), coachMarkDimenInPixel.getNotchDimenInPixels());
+ notchMarginRect = new Rect(notchPosition + coachMarkDimenInPixel.getMarginOffsetForNotchInPixels(), -coachMarkDimenInPixel.getMarginOffsetForNotchInPixels(), NO_MARGIN, NO_MARGIN);
+ mPopUpCoachMarkPresentation.setNotchPositionIfPopUpTopLeft(notchMarginRect, ROTATION_180);
+ break;
+ case PopUpPosition.RIGHT:
+ actualTopMargin = getActualTopMargin(centerY, coachMarkDimenInPixel);
+ coachMarkMarginRect = new Rect(coachMarkDimenInPixel.getMarginRectInPixels().left + coachMarkDimenInPixel.getImageWidthInPixels(), actualTopMargin - coachMarkDimenInPixel.getMarginRectInPixels().bottom, coachMarkDimenInPixel.getMarginRectInPixels().right, NO_MARGIN);
+ mPopUpCoachMarkPresentation.setPopUpViewBottomRight(coachMarkMarginRect, CoachMarkLayoutOrientation.HORIZONTAL);
+ notchPosition = getMarginTopForNotch(mCoachMarkBuilder.getNotchPosition(), coachMarkDimenInPixel.getPopUpHeightInPixels(), coachMarkDimenInPixel.getNotchDimenInPixels());
+ notchMarginRect = new Rect(NO_MARGIN, notchPosition - (2 * coachMarkDimenInPixel.getMarginOffsetForNotchInPixels()), NO_MARGIN, NO_MARGIN);
+ mPopUpCoachMarkPresentation.setNotchPositionIfPopUpBottomRight(notchMarginRect, ROTATION_270);
+ notchUiAdjustmentMarginRect = new Rect(NO_MARGIN, notchPosition - coachMarkDimenInPixel.getMarginOffsetForNotchInPixels(), NO_MARGIN, NO_MARGIN);
+ mPopUpCoachMarkPresentation.uiAdjustmentForNotchIfPopUpRight(notchUiAdjustmentMarginRect);
+ break;
+ case PopUpPosition.BOTTOM:
+ actualLeftMargin = getActualLeftMargin(anchorTopX, coachMarkDimenInPixel);
+ coachMarkMarginRect = new Rect(actualLeftMargin - coachMarkDimenInPixel.getMarginRectInPixels().right, coachMarkDimenInPixel.getMarginRectInPixels().top + coachMarkDimenInPixel.getImageHeightInPixels(), NO_MARGIN, coachMarkDimenInPixel.getMarginRectInPixels().bottom);
+ mPopUpCoachMarkPresentation.setPopUpViewBottomRight(coachMarkMarginRect, CoachMarkLayoutOrientation.VERTICAL);
+ notchPosition = getMarginLeftForNotch(mCoachMarkBuilder.getNotchPosition(), coachMarkDimenInPixel.getPopUpWidthInPixels(), coachMarkDimenInPixel.getNotchDimenInPixels());
+ notchMarginRect = new Rect(notchPosition + coachMarkDimenInPixel.getMarginOffsetForNotchInPixels(), NO_MARGIN, NO_MARGIN, NO_MARGIN);
+ mPopUpCoachMarkPresentation.setNotchPositionIfPopUpBottomRight(notchMarginRect, ROTATION_0);
+ notchUiAdjustmentMarginRect = new Rect(notchPosition + MULTIPLICATION_FACTOR_FOR_NOTCH_UI_ADJUSTMENT * coachMarkDimenInPixel.getMarginOffsetForNotchInPixels(), NO_MARGIN, NO_MARGIN, NO_MARGIN);
+ mPopUpCoachMarkPresentation.uiAdjustmentForNotchIfPopUpBottom(notchUiAdjustmentMarginRect);
+ break;
+ }
+ }
+
+ private int getMarginLeftForNotch(double notchPosition, int popUpWidth, int notchDimen) {
+ if (notchPosition > MAX_NOTCH_RANGE)
+ notchPosition = MAX_NOTCH_RANGE;
+ if (notchPosition <= MIN_NOTCH_RANGE)
+ notchPosition = MIN_NOTCH_RANGE;
+ int marginLeft = (int) (popUpWidth * notchPosition);
+ if (marginLeft > popUpWidth - notchDimen)
+ return (popUpWidth - notchDimen);
+ return marginLeft;
+ }
+
+ private int getMarginTopForNotch(double notchPosition, int popUpHeight, int notchDimen) {
+ if (notchPosition > MAX_NOTCH_RANGE)
+ notchPosition = MAX_NOTCH_RANGE;
+ if (notchPosition <= MIN_NOTCH_RANGE)
+ notchPosition = MIN_NOTCH_RANGE;
+ int marginTop = (int) (popUpHeight * notchPosition);
+ if (marginTop > popUpHeight - notchDimen)
+ return (popUpHeight - notchDimen);
+ return marginTop;
+ }
+
+ private void detectAndCreateShimOutViews(@Nullable List infoForViewToMaskList) {
+ if (infoForViewToMaskList == null) {
+ return;
+ }
+ for (InfoForViewToMask infoForViewToMask : infoForViewToMaskList) {
+ mPopUpCoachMarkPresentation.createViewToBeMaskedOut(
+ infoForViewToMask.getViewToMaskStartPosition().x,
+ infoForViewToMask.getViewToMaskStartPosition().y,
+ infoForViewToMask.getViewToMaskHeight(),
+ infoForViewToMask.getViewToMaskWidth());
+ }
+ }
+
+ private int findCoachMarkTextPopUpDisplayPosition(Point anchorTop, Point anchorBottom,
+ @PopUpPosition int defaultPopUpPosition,
+ CoachMarkPixelInfo coachMarkDimenInPixel) {
+ int centerX = (anchorTop.x + anchorBottom.x) / 2;
+ int centerY = (anchorTop.y + anchorBottom.y) / 2;
+ Point centerViewPoint = new Point(centerX, centerY);
+ @PopUpPosition
+ int popUpPosition = getDisplayPosition(centerViewPoint,
+ defaultPopUpPosition, coachMarkDimenInPixel);
+ return popUpPosition;
+ }
+
+ private void createAnimationOnImage(@AnimationType int animationType) {
+ switch (animationType) {
+ case AnimationType.THROB_ANIMATION:
+ mPopUpCoachMarkPresentation.startThrobAnimationOnImage();
+ break;
+ case AnimationType.ALPHA_ANIMATION:
+ mPopUpCoachMarkPresentation.startAlphaAnimationOnImage();
+ break;
+ case AnimationType.SCALE_ANIMATION:
+ mPopUpCoachMarkPresentation.startScaleAnimationOnImage();
+ break;
+ case AnimationType.ANIMATION_NONE:
+ break;
+ }
+ }
+
+ private void setImageParamsAndPosition(Point anchorTop, Point anchorBottom,
+ int imageWidth, int imageHeight,
+ @ColorRes int backGroundTintForImage,
+ @DrawableRes int imageDrawableRes) {
+ double centerX = (anchorTop.x + anchorBottom.x) / 2;
+ double centerY = (anchorTop.y + anchorBottom.y) / 2;
+ mPopUpCoachMarkPresentation.setImageInformation(centerX, centerY, imageWidth,
+ imageHeight, backGroundTintForImage, imageDrawableRes);
+ }
+
+ private void showCoachMark(@DialogDismissButtonPosition int dismissButtonPosition,
+ @PopUpPosition int popUpPosition) {
+
+ switch (popUpPosition) {
+ case PopUpPosition.LEFT:
+ mPopUpCoachMarkPresentation.setPopUpViewPositionWithRespectToImage(CoachMarkAlignPosition.ALIGN_RIGHT);
+ break;
+ case PopUpPosition.TOP:
+ mPopUpCoachMarkPresentation.setPopUpViewPositionWithRespectToImage(CoachMarkAlignPosition.ALIGN_BOTTOM);
+ break;
+ case PopUpPosition.RIGHT:
+ mPopUpCoachMarkPresentation.setPopUpViewPositionWithRespectToImage(CoachMarkAlignPosition.ALIGN_LEFT);
+ break;
+ case PopUpPosition.BOTTOM:
+ mPopUpCoachMarkPresentation.setPopUpViewPositionWithRespectToImage(CoachMarkAlignPosition.ALIGN_TOP);
+ break;
+ case PopUpPosition.NONE:
+ //TODO:: Handle this case
+ break;
+ }
+
+ switch (dismissButtonPosition) {
+ case DialogDismissButtonPosition.LEFT:
+ mPopUpCoachMarkPresentation.setDismissButtonPositionLeft();
+ break;
+ case DialogDismissButtonPosition.RIGHT:
+ mPopUpCoachMarkPresentation.setDismissButtonPositionRight();
+ break;
+ }
+ }
+
+ @PopUpPosition
+ private int getDisplayPosition(Point viewCenterPoint,
+ @PopUpPosition int defaultPopUpPosition,
+ CoachMarkPixelInfo coachMarkDimenInPixel) {
+ @PopUpPosition
+ int correctPosition = 0;
+ switch (defaultPopUpPosition) {
+ case PopUpPosition.LEFT:
+ if (checkIfLeftPossible(viewCenterPoint, coachMarkDimenInPixel)) {
+ correctPosition = defaultPopUpPosition;
+ } else {
+ correctPosition = getCorrectPositionOfCoachMarkIfDefaultFails(viewCenterPoint, coachMarkDimenInPixel);
+ }
+ break;
+ case PopUpPosition.RIGHT:
+ if (checkIfRightPossible(viewCenterPoint, coachMarkDimenInPixel)) {
+ correctPosition = defaultPopUpPosition;
+ } else {
+ correctPosition = getCorrectPositionOfCoachMarkIfDefaultFails(viewCenterPoint, coachMarkDimenInPixel);
+ }
+ break;
+
+ case PopUpPosition.BOTTOM:
+ if (checkIfBottomPossible(viewCenterPoint, coachMarkDimenInPixel)) {
+ correctPosition = defaultPopUpPosition;
+ } else {
+ correctPosition = getCorrectPositionOfCoachMarkIfDefaultFails(viewCenterPoint, coachMarkDimenInPixel);
+ }
+ break;
+
+ case PopUpPosition.TOP:
+ if (checkIfTopPossible(viewCenterPoint, coachMarkDimenInPixel)) {
+ correctPosition = defaultPopUpPosition;
+ } else {
+ correctPosition = getCorrectPositionOfCoachMarkIfDefaultFails(viewCenterPoint, coachMarkDimenInPixel);
+ }
+ break;
+ case PopUpPosition.NONE:
+ //TODO:: Handle this
+ break;
+ }
+ return correctPosition;
+ }
+
+ private boolean checkIfLeftPossible(Point viewCenterPoint, CoachMarkPixelInfo coachMarkDimenInPixel) {
+ int centerX = viewCenterPoint.x;
+ return (coachMarkDimenInPixel.getPopUpWidthInPixelsWithOffset() + coachMarkDimenInPixel.getMarginRectInPixels().right + coachMarkDimenInPixel.getMarginRectInPixels().left) < centerX && ((coachMarkDimenInPixel.getPopUpHeightInPixelsWithOffset() + coachMarkDimenInPixel.getMarginRectInPixels().top + coachMarkDimenInPixel.getActionBarHeightPixels() + coachMarkDimenInPixel.getFooterHeightPixels() + coachMarkDimenInPixel.getMarginRectInPixels().bottom) <= coachMarkDimenInPixel.getScreenHeightInPixels());
+ }
+
+ private boolean checkIfRightPossible(Point viewCenterPoint, CoachMarkPixelInfo coachMarkDimenInPixel) {
+ int centerX = viewCenterPoint.x;
+ return (coachMarkDimenInPixel.getPopUpWidthInPixelsWithOffset() + coachMarkDimenInPixel.getMarginRectInPixels().right + coachMarkDimenInPixel.getMarginRectInPixels().left) <= (coachMarkDimenInPixel.getScreenWidthInPixels() - centerX) && ((coachMarkDimenInPixel.getPopUpHeightInPixelsWithOffset() + coachMarkDimenInPixel.getMarginRectInPixels().top + coachMarkDimenInPixel.getActionBarHeightPixels() + coachMarkDimenInPixel.getFooterHeightPixels() + coachMarkDimenInPixel.getMarginRectInPixels().bottom) <= coachMarkDimenInPixel.getScreenHeightInPixels());
+ }
+
+ private boolean checkIfTopPossible(Point viewCenterPoint, CoachMarkPixelInfo coachMarkDimenInPixel) {
+ int centerY = viewCenterPoint.y;
+ return (coachMarkDimenInPixel.getPopUpHeightInPixelsWithOffset() + coachMarkDimenInPixel.getMarginRectInPixels().top + coachMarkDimenInPixel.getMarginRectInPixels().bottom + coachMarkDimenInPixel.getActionBarHeightPixels()) <= centerY && ((coachMarkDimenInPixel.getWidthHeightOffsetForCoachMarkPopUp() + coachMarkDimenInPixel.getMarginRectInPixels().left + coachMarkDimenInPixel.getMarginRectInPixels().right) <= coachMarkDimenInPixel.getScreenWidthInPixels());
+ }
+
+ private boolean checkIfBottomPossible(Point viewCenterPoint, CoachMarkPixelInfo coachMarkDimenInPixel) {
+ int centerY = viewCenterPoint.y;
+ return (coachMarkDimenInPixel.getPopUpHeightInPixelsWithOffset() + coachMarkDimenInPixel.getMarginRectInPixels().top + coachMarkDimenInPixel.getMarginRectInPixels().bottom + coachMarkDimenInPixel.getFooterHeightPixels()) <= coachMarkDimenInPixel.getScreenHeightInPixels() - centerY && ((coachMarkDimenInPixel.getPopUpWidthInPixelsWithOffset() + coachMarkDimenInPixel.getMarginRectInPixels().left + coachMarkDimenInPixel.getMarginRectInPixels().right) <= coachMarkDimenInPixel.getScreenWidthInPixels());
+ }
+
+ @PopUpPosition
+ private int getCorrectPositionOfCoachMarkIfDefaultFails(Point viewCenterPoint, CoachMarkPixelInfo coachMarkDimenInPixel) {
+
+ @PopUpPosition int correctPopUpPosition = PopUpPosition.NONE;
+
+ if (checkIfRightPossible(viewCenterPoint, coachMarkDimenInPixel))
+ correctPopUpPosition = PopUpPosition.RIGHT;
+ else if (checkIfBottomPossible(viewCenterPoint, coachMarkDimenInPixel))
+ correctPopUpPosition = PopUpPosition.BOTTOM;
+ else if (checkIfLeftPossible(viewCenterPoint, coachMarkDimenInPixel))
+ correctPopUpPosition = PopUpPosition.LEFT;
+ else if (checkIfTopPossible(viewCenterPoint, coachMarkDimenInPixel))
+ correctPopUpPosition = PopUpPosition.TOP;
+
+ return correctPopUpPosition;
+ }
+
+ private CoachMarkPixelInfo createCoachMarkPixelInfo() {
+ final CoachMarkLayoutMargin coachMarkLayoutMargin = mCoachMarkBuilder.getCoachMarkLayoutMargin();
+ int leftMargin = mDimensionResourceProvider.getDimensionInPixel(coachMarkLayoutMargin.getLeftMarginForCoachMark());
+ int rightMargin = mDimensionResourceProvider.getDimensionInPixel(coachMarkLayoutMargin.getRightMarginForCoachMark());
+ int topMargin = mDimensionResourceProvider.getDimensionInPixel(coachMarkLayoutMargin.getTopMarginForCoachMark());
+ int bottomMargin = mDimensionResourceProvider.getDimensionInPixel(coachMarkLayoutMargin.getBottomMarginForCoachMark());
+
+ int actionBarHeightPixels = mDimensionResourceProvider.getDimensionInPixel(mCoachMarkBuilder.getActionBarHeight());
+ int footerHeightPixels = mDimensionResourceProvider.getDimensionInPixel(mCoachMarkBuilder.getFooterHeight());
+
+ int imageHeightInPixels = mDimensionResourceProvider.getDimensionInPixel(mCoachMarkBuilder.getImageLayoutInformation().getImageHeight());
+ int imageWidthInPixels = mDimensionResourceProvider.getDimensionInPixel(mCoachMarkBuilder.getImageLayoutInformation().getImageWidth());
+
+ int coachMarkPopUpHeightInPixels = mDimensionResourceProvider.getDimensionInPixel(R.dimen.coach_mark_pop_up_height);
+ int coachMarkPopUpWidthInPixels = mDimensionResourceProvider.getDimensionInPixel(R.dimen.coach_mark_pop_up_width);
+
+ int notchDimenInPixels = mDimensionResourceProvider.getDimensionInPixel(R.dimen.coach_mark_notch_width_height);
+ int marginOffsetForNotchInPixels = mDimensionResourceProvider.getDimensionInPixel(R.dimen.coach_mark_notch_margin_offset);
+
+ int widthHeightOffsetForCoachMarkPopUp = mDimensionResourceProvider.getDimensionInPixel(R.dimen.coach_mark_pop_up_width_height_offset);
+ int coachMarkPopUpWidthInPixelsWithOffset = coachMarkPopUpWidthInPixels + widthHeightOffsetForCoachMarkPopUp + imageWidthInPixels;
+ int coachMarkPopUpHeightInPixelsWithOffset = coachMarkPopUpHeightInPixels + widthHeightOffsetForCoachMarkPopUp + imageHeightInPixels;
+
+ int screenHeightInPixels = mScreenInfoProvider.getScreenHeightInPixels();
+ int screenWidthInPixels = mScreenInfoProvider.getScreenWidthInPixels();
+
+ return CoachMarkPixelInfo.create()
+ .setMarginRectInPixels(new Rect(leftMargin, topMargin, rightMargin, bottomMargin))
+ .setPopUpHeightInPixels(coachMarkPopUpHeightInPixels)
+ .setPopUpHeightInPixelsWithOffset(coachMarkPopUpHeightInPixelsWithOffset)
+ .setPopUpWidthInPixels(coachMarkPopUpWidthInPixels)
+ .setPopUpWidthInPixelsWithOffset(coachMarkPopUpWidthInPixelsWithOffset)
+ .setWidthHeightOffsetForCoachMarkPopUp(widthHeightOffsetForCoachMarkPopUp)
+ .setActionBarHeightPixels(actionBarHeightPixels)
+ .setFooterHeightPixels(footerHeightPixels)
+ .setNotchDimenInPixels(notchDimenInPixels)
+ .setMarginOffsetForNotchInPixels(marginOffsetForNotchInPixels)
+ .setImageHeightInPixels(imageHeightInPixels)
+ .setImageWidthInPixels(imageWidthInPixels)
+ .setScreenHeightInPixels(screenHeightInPixels)
+ .setScreenWidthInPixels(screenWidthInPixels)
+ .build();
+ }
+
+ private int getActualTopMargin(int centerTopY, CoachMarkPixelInfo coachMarkDimenInPixel) {
+ if (centerTopY + coachMarkDimenInPixel.getPopUpHeightInPixels() + coachMarkDimenInPixel.getWidthHeightOffsetForCoachMarkPopUp() + coachMarkDimenInPixel.getMarginRectInPixels().top + coachMarkDimenInPixel.getMarginRectInPixels().bottom > coachMarkDimenInPixel.getScreenHeightInPixels()) {
+ return coachMarkDimenInPixel.getScreenHeightInPixels() - coachMarkDimenInPixel.getPopUpHeightInPixels() + coachMarkDimenInPixel.getWidthHeightOffsetForCoachMarkPopUp() + coachMarkDimenInPixel.getMarginRectInPixels().top + coachMarkDimenInPixel.getMarginRectInPixels().bottom;
+ }
+ return centerTopY + coachMarkDimenInPixel.getMarginRectInPixels().top;
+ }
+
+ private int getActualLeftMargin(int anchorTopX, CoachMarkPixelInfo coachMarkDimenInPixel) {
+ if (anchorTopX + coachMarkDimenInPixel.getPopUpWidthInPixels() + coachMarkDimenInPixel.getWidthHeightOffsetForCoachMarkPopUp() + coachMarkDimenInPixel.getMarginRectInPixels().right + coachMarkDimenInPixel.getMarginRectInPixels().left > coachMarkDimenInPixel.getScreenWidthInPixels()) {
+ return coachMarkDimenInPixel.getScreenWidthInPixels() - coachMarkDimenInPixel.getPopUpWidthInPixels() + coachMarkDimenInPixel.getWidthHeightOffsetForCoachMarkPopUp() + coachMarkDimenInPixel.getMarginRectInPixels().right + coachMarkDimenInPixel.getMarginRectInPixels().left;
+ }
+ return anchorTopX + coachMarkDimenInPixel.getMarginRectInPixels().left;
+ }
+ //endregion
+}
diff --git a/coachmarks/src/main/java/com/myntra/coachmarks/ui/utils/TransitionUtils.java b/coachmarks/src/main/java/com/myntra/coachmarks/ui/utils/TransitionUtils.java
new file mode 100644
index 0000000..2c5eba4
--- /dev/null
+++ b/coachmarks/src/main/java/com/myntra/coachmarks/ui/utils/TransitionUtils.java
@@ -0,0 +1,52 @@
+package com.myntra.coachmarks.ui.utils;
+
+import android.animation.ValueAnimator;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.AlphaAnimation;
+import android.view.animation.Animation;
+import android.view.animation.AnimationSet;
+import android.view.animation.ScaleAnimation;
+
+public class TransitionUtils {
+
+ private static final int ALPHA_ANIMATION_DURATION = 2000;
+ private static final double ALPHA_ANIMATION_FROM = 1;
+ private static final double ALPHA_ANIMATION_TO = 0;
+ private static final double SCALE_ANIMATION_FROM_X = 1;
+ private static final double SCALE_ANIMATION_TO_X = 1.5;
+ private static final double SCALE_ANIMATION_FROM_Y = 1;
+ private static final double SCALE_ANIMATION_TO_Y = 1.5;
+ private static final double SCALE_ANIMATION_PIVOT_X = .5;
+ private static final double SCALE_ANIMATION_PIVOT_Y = .5;
+ private static final int SCALE_ANIMATION_DURATION = 2000;
+
+ public static AnimationSet createThrobAnimation() {
+ AnimationSet animationSet = new AnimationSet(false);
+ animationSet.addAnimation(createAlphaAnimation());
+ animationSet.addAnimation(createScaleAnimation());
+ return animationSet;
+ }
+
+ public static Animation createAlphaAnimation() {
+ ScaleAnimation scaleAnimation = new ScaleAnimation((float) SCALE_ANIMATION_FROM_X,
+ (float) SCALE_ANIMATION_TO_X, (float) SCALE_ANIMATION_FROM_Y,
+ (float) SCALE_ANIMATION_TO_Y, Animation.RELATIVE_TO_SELF,
+ (float) SCALE_ANIMATION_PIVOT_X, Animation.RELATIVE_TO_SELF,
+ (float) SCALE_ANIMATION_PIVOT_Y);
+ scaleAnimation.setDuration(SCALE_ANIMATION_DURATION);
+ scaleAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
+ scaleAnimation.setRepeatCount(ValueAnimator.INFINITE);
+ scaleAnimation.setRepeatMode(ValueAnimator.RESTART);
+ return scaleAnimation;
+ }
+
+ public static Animation createScaleAnimation() {
+ AlphaAnimation alphaAnimation = new AlphaAnimation((float) ALPHA_ANIMATION_FROM,
+ (float) ALPHA_ANIMATION_TO);
+ alphaAnimation.setDuration(ALPHA_ANIMATION_DURATION);
+ alphaAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
+ alphaAnimation.setRepeatCount(ValueAnimator.INFINITE);
+ alphaAnimation.setRepeatMode(ValueAnimator.RESTART);
+ return alphaAnimation;
+ }
+}
diff --git a/coachmarks/src/main/res/drawable/background_shadow_drawable.xml b/coachmarks/src/main/res/drawable/background_shadow_drawable.xml
new file mode 100644
index 0000000..c7909f9
--- /dev/null
+++ b/coachmarks/src/main/res/drawable/background_shadow_drawable.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/coachmarks/src/main/res/drawable/coach_mark_vertical_dashed_line_separator.xml b/coachmarks/src/main/res/drawable/coach_mark_vertical_dashed_line_separator.xml
new file mode 100644
index 0000000..7a4eb24
--- /dev/null
+++ b/coachmarks/src/main/res/drawable/coach_mark_vertical_dashed_line_separator.xml
@@ -0,0 +1,16 @@
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/coachmarks/src/main/res/drawable/coachmark_drawable_no_image.xml b/coachmarks/src/main/res/drawable/coachmark_drawable_no_image.xml
new file mode 100644
index 0000000..471369b
--- /dev/null
+++ b/coachmarks/src/main/res/drawable/coachmark_drawable_no_image.xml
@@ -0,0 +1,5 @@
+
+
+
+
\ No newline at end of file
diff --git a/coachmarks/src/main/res/drawable/coachmark_pop_up_drawable.xml b/coachmarks/src/main/res/drawable/coachmark_pop_up_drawable.xml
new file mode 100644
index 0000000..0d76940
--- /dev/null
+++ b/coachmarks/src/main/res/drawable/coachmark_pop_up_drawable.xml
@@ -0,0 +1,19 @@
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+
diff --git a/coachmarks/src/main/res/drawable/triangle_up.xml b/coachmarks/src/main/res/drawable/triangle_up.xml
new file mode 100644
index 0000000..1bb7dac
--- /dev/null
+++ b/coachmarks/src/main/res/drawable/triangle_up.xml
@@ -0,0 +1,17 @@
+
+
+ -
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/coachmarks/src/main/res/layout/pop_up_coach_mark.xml b/coachmarks/src/main/res/layout/pop_up_coach_mark.xml
new file mode 100644
index 0000000..c956f04
--- /dev/null
+++ b/coachmarks/src/main/res/layout/pop_up_coach_mark.xml
@@ -0,0 +1,121 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/coachmarks/src/main/res/values-v21/styles.xml b/coachmarks/src/main/res/values-v21/styles.xml
new file mode 100644
index 0000000..f462ea2
--- /dev/null
+++ b/coachmarks/src/main/res/values-v21/styles.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/coachmarks/src/main/res/values/attrs.xml b/coachmarks/src/main/res/values/attrs.xml
new file mode 100644
index 0000000..0d2c4cc
--- /dev/null
+++ b/coachmarks/src/main/res/values/attrs.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/coachmarks/src/main/res/values/color.xml b/coachmarks/src/main/res/values/color.xml
new file mode 100644
index 0000000..4fbc8e4
--- /dev/null
+++ b/coachmarks/src/main/res/values/color.xml
@@ -0,0 +1,16 @@
+
+
+
+ #00000000
+ #3E4152
+ #526cd0
+ #D4D5D9
+ #FFFFFF
+ #70000000
+ #50000000
+ #bfc0c6
+ #1B202A
+ #0BC6A0
+ #FFFFFF
+
+
\ No newline at end of file
diff --git a/coachmarks/src/main/res/values/dimens.xml b/coachmarks/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..e8a3deb
--- /dev/null
+++ b/coachmarks/src/main/res/values/dimens.xml
@@ -0,0 +1,40 @@
+
+
+
+ 10dp
+ 0dp
+ 10dp
+ 3dp
+ 2dp
+
+ 210dp
+ 50dp
+ 50dp
+ 50dp
+ 50dp
+ 12dp
+ 48dp
+ 12dp
+ 145dp
+ 50dp
+ 2dp
+ 2dp
+ 2dp
+ 13dp
+ 8dp
+ 146dp
+ 8dp
+ 6dp
+
+ 14sp
+ 6dp
+ 8dp
+ 16dp
+
+ 20dp
+ 16dp
+ 17dp
+ 1dp
+
+
+
\ No newline at end of file
diff --git a/coachmarks/src/main/res/values/integers.xml b/coachmarks/src/main/res/values/integers.xml
new file mode 100644
index 0000000..71c892d
--- /dev/null
+++ b/coachmarks/src/main/res/values/integers.xml
@@ -0,0 +1,5 @@
+
+
+ 2
+ 3
+
\ No newline at end of file
diff --git a/coachmarks/src/main/res/values/strings.xml b/coachmarks/src/main/res/values/strings.xml
new file mode 100644
index 0000000..5c8ad8e
--- /dev/null
+++ b/coachmarks/src/main/res/values/strings.xml
@@ -0,0 +1,6 @@
+
+
+ OK
+ Coachmark cannot be displayed
+
+
diff --git a/coachmarks/src/main/res/values/styles.xml b/coachmarks/src/main/res/values/styles.xml
new file mode 100644
index 0000000..0b4eea0
--- /dev/null
+++ b/coachmarks/src/main/res/values/styles.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/coachmarks/src/test/java/com/myntra/coachmarks/CoachMarkUnitTest.java b/coachmarks/src/test/java/com/myntra/coachmarks/CoachMarkUnitTest.java
new file mode 100644
index 0000000..5a9add4
--- /dev/null
+++ b/coachmarks/src/test/java/com/myntra/coachmarks/CoachMarkUnitTest.java
@@ -0,0 +1,12 @@
+package com.myntra.coachmarks;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class CoachMarkUnitTest {
+ @Test
+ public void addition_isCorrect() throws Exception {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/coachmarks/src/test/java/com/myntra/coachmarks/ui/presenter/PopUpCoachMarkPresenterTest.java b/coachmarks/src/test/java/com/myntra/coachmarks/ui/presenter/PopUpCoachMarkPresenterTest.java
new file mode 100644
index 0000000..247567a
--- /dev/null
+++ b/coachmarks/src/test/java/com/myntra/coachmarks/ui/presenter/PopUpCoachMarkPresenterTest.java
@@ -0,0 +1,35 @@
+package com.myntra.coachmarks.ui.presenter;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author mudit.pant on 28/02/17.
+ */
+public class PopUpCoachMarkPresenterTest {
+ @Before
+ public void setUp() throws Exception {
+
+ }
+
+ @Test
+ public void onCreate() throws Exception {
+
+ }
+
+ @Test
+ public void onDestroy() throws Exception {
+
+ }
+
+ @Test
+ public void onOkButtonClicked() throws Exception {
+
+ }
+
+ @Test
+ public void onShimClicked() throws Exception {
+
+ }
+
+}
\ No newline at end of file
diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml
new file mode 100644
index 0000000..71c2508
--- /dev/null
+++ b/config/checkstyle/checkstyle.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/config/checkstyle/suppressions.xml b/config/checkstyle/suppressions.xml
new file mode 100755
index 0000000..49e9b41
--- /dev/null
+++ b/config/checkstyle/suppressions.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/config/findbugs/findbugs.xml b/config/findbugs/findbugs.xml
new file mode 100755
index 0000000..dc06b9d
--- /dev/null
+++ b/config/findbugs/findbugs.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/config/lint/lint.xml b/config/lint/lint.xml
new file mode 100755
index 0000000..c717ea7
--- /dev/null
+++ b/config/lint/lint.xml
@@ -0,0 +1,154 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/config/pmd/pmd.xml b/config/pmd/pmd.xml
new file mode 100755
index 0000000..f792968
--- /dev/null
+++ b/config/pmd/pmd.xml
@@ -0,0 +1,30 @@
+
+
+
+ Custom ruleset for Android application
+
+ .*/R.java
+ .*/gen/.*
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/contributors.txt b/contributors.txt
new file mode 100644
index 0000000..0c96244
--- /dev/null
+++ b/contributors.txt
@@ -0,0 +1,3 @@
+#
+Myntra
+Manjunath Chandrashekar (manjunath.c1@myntra.com, mudit.pant@myntra.com)
diff --git a/dependencies.gradle b/dependencies.gradle
new file mode 100644
index 0000000..7e70a34
--- /dev/null
+++ b/dependencies.gradle
@@ -0,0 +1,206 @@
+ext.versions = [
+ compileSdk : 25,
+ minSdk : 16,
+ targetSdk : 24,
+ buildTools : "25.0.2",
+
+ supportLibVersion : "25.1.0",
+ playServicesVersion : "10.0.1",
+ dexmakerVersion : "1.2",
+ multiDexVersion : "1.0.1",
+
+ facebookSdkVersion : "4.18.0",
+
+ butterKnifeVersion : "8.5.1",
+ bundlerVersion : "1.1.2",
+ eventBusVersion : "3.0.0",
+
+ javaxAnnotationApiVersion : "1.2",
+ jsr305Version : "2.0.1",
+
+ ormliteVersion : "4.48",
+ prettyTimeVersion : "3.2.7.Final",
+
+ autoValue : "1.3",
+ autoValueParcel : "0.2.5",
+
+ daggerVersion : "2.9",
+ retrofitVersion : "2.1.0",
+ rxJavaVersion : "1.2.4",
+ rxAndroidVersion : "1.2.1",
+
+ gsonVersion : "2.8",
+ cookiesJarVersion : "v1.0.0",
+ networkSamplerVersion : "connectionclass:1.0.1",
+
+ okIoVersion : "1.11.0",
+ okHttp3Version : "3.5.0",
+
+ glideVersion : "3.7.0",
+ glideOkHttpVersion : "1.4.0",
+
+ lynxVersion : '1.6',
+ stethoVersion : '1.3.1',
+ tinyDancerVersion : '0.1.0',
+ timberVersion : "4.1.2",
+ leakcanaryVersion : "1.5",
+
+ zetaUtilsVersion : "0.4",
+ zetaEitherVersion : "0.3",
+ zetaListItemDividerVersion : "0.2",
+ zetaHeaderAndFooterAdaptersVersion: "0.2",
+
+ lottieAnimationVersion : "1.5.1",
+
+ junitVersion : '4.12',
+ robolectricVersion : '3.0',
+ assertJVersion : '1.7.1',
+ equalsVerifierVersion : '1.7.5',
+ mockitoVersion : '1.10.19',
+ supportTestRunnerVersion : '0.4.1',
+ supportTestVersion : "0.4.1",
+ espressoVersion : '2.2.1',
+
+ aptPluginVersion : "1.8",
+ gradlePluginVersion : "2.3.0",
+ retroLambdaPluginVersion : "3.2.5",
+ retrolombokPluginVersion : "0.2.3.a2",
+ frodoPluginVersion : "0.8.3",
+ gmsServicesPluginVersion : "3.0.0",
+]
+
+ext.gradlePlugins = [
+ aptPlugin : "com.neenbedankt.gradle.plugins:android-apt:$versions.aptPluginVersion",
+ androidToolsPlugin: "com.android.tools.build:gradle:$versions.gradlePluginVersion",
+ retroLambdaPlugin : "me.tatarka:gradle-retrolambda:$versions.retroLambdaPluginVersion",
+ frodoPlugin : "com.fernandocejas.frodo:frodo-plugin:$versions.frodoPluginVersion",
+ butterKnifePlugin : "com.jakewharton:butterknife-gradle-plugin:$versions.butterKnifeVersion",
+ lombokPlugin : "me.tatarka.retrolambda.projectlombok:lombok.ast:$versions.retrolombokPluginVersion",
+ gmsServicesPlugin : "com.google.gms:google-services:$versions.gmsServicesPluginVersion",
+]
+
+ext.libraries = [
+
+ //region support libraries
+ supportDesign : "com.android.support:design:$versions.supportLibVersion",
+ supportMultiDex : "com.android.support:multidex:$versions.multiDexVersion",
+ supportV4 : "com.android.support:support-v4:$versions.supportLibVersion",
+ supportV13 : "com.android.support:support-v13:$versions.supportLibVersion",
+ supportCardView : "com.android.support:cardview-v7:$versions.supportLibVersion",
+ supportAppCompat : "com.android.support:appcompat-v7:$versions.supportLibVersion",
+ supportRecyclerView : "com.android.support:recyclerview-v7:$versions.supportLibVersion",
+ supportAnnotations : "com.android.support:support-annotations:$versions.supportLibVersion",
+ //endregion
+
+ //custom tabs
+ chromeCustomTab : "com.android.support:customtabs:$versions.supportLibVersion",
+ //endregion
+
+ //region play services
+ playServicesGcm : "com.google.android.gms:play-services-gcm:$versions.playServicesVersion",
+ playServicesAd : "com.google.android.gms:play-services-ads:$versions.playServicesVersion",
+ playServicesMaps : "com.google.android.gms:play-services-maps:$versions.playServicesVersion",
+ playServicesPlaces : "com.google.android.gms:play-services-places:$versions.playServicesVersion",
+ playServicesLocation : "com.google.android.gms:play-services-location:$versions.playServicesVersion",
+ playServicesAuthentication : "com.google.android.gms:play-services-auth:$versions.playServicesVersion",
+ //endregion
+
+ //region firebase
+ appIndexing : "com.google.firebase:firebase-appindexing:$versions.playServicesVersion",
+ //endregion
+
+ //region facebook
+ facebookSdk : "com.facebook.android:facebook-android-sdk:$versions.facebookSdkVersion",
+ //endregion
+
+ //region IMAGE PROCESSOR
+ glide : "com.github.bumptech.glide:glide:$versions.glideVersion",
+ glideOkHttp : "com.github.bumptech.glide:okhttp3-integration:$versions.glideOkHttpVersion",
+ //endregion
+
+ //region DEPENDENCIES INJECTION
+ dagger : "com.google.dagger:dagger:$versions.daggerVersion",
+ daggerCompiler : "com.google.dagger:dagger-compiler:$versions.daggerVersion",
+ //endregion
+
+ //region NETWORK
+ okio : "com.squareup.okio:okio:$versions.okIoVersion",
+ okHttp3 : "com.squareup.okhttp3:okhttp:$versions.okHttp3Version",
+ okHttp3LogInterceptor : "com.squareup.okhttp3:logging-interceptor:$versions.okHttp3Version",
+
+ retrofit : "com.squareup.retrofit2:retrofit:$versions.retrofitVersion",
+ retrofitGsonConverter : "com.squareup.retrofit2:converter-gson:$versions.retrofitVersion",
+ retrofitRxAdapter : "com.squareup.retrofit2:adapter-rxjava:$versions.retrofitVersion",
+
+ rxJava : "io.reactivex:rxjava:$versions.rxJavaVersion",
+ rxAndroid : "io.reactivex:rxandroid:$versions.rxAndroidVersion",
+
+ gson : "com.google.code.gson:gson:$versions.gsonVersion",
+
+ networkSampler : "com.facebook.network.connectionclass:$versions.networkSamplerVersion",
+ persistentCookieJar : "com.github.franmontiel:PersistentCookieJar:$versions.cookiesJarVersion",
+ //endregion
+
+ //region UTILS
+ autoValue : "com.google.auto.value:auto-value:$versions.autoValue",
+ autoValueParcel : "com.ryanharter.auto.value:auto-value-parcel:$versions.autoValueParcel",
+ autoValueParcelAdapter : "com.ryanharter.auto.value:auto-value-parcel-adapter:$versions.autoValueParcel",
+
+ butterKnife : "com.jakewharton:butterknife:$versions.butterKnifeVersion",
+ butterKnifeCompiler : "com.jakewharton:butterknife-compiler:$versions.butterKnifeVersion",
+
+ eventBus : "org.greenrobot:eventbus:$versions.eventBusVersion",
+ bundler : "com.f2prateek.bundler:bundler:$versions.bundlerVersion",
+ prettyTime : "org.ocpsoft.prettytime:prettytime:$versions.prettyTimeVersion",
+ //endregion
+
+ //region DATABASE
+ ormlite : "com.j256.ormlite:ormlite-android:$versions.ormliteVersion",
+ //endregion
+
+ //region ANNOTATION
+ jsr305 : "com.google.code.findbugs:jsr305:$versions.jsr305Version",
+ javaxAnnotationApi : "javax.annotation:javax.annotation-api:$versions.javaxAnnotationApiVersion",
+ //endregion
+
+ //region zeta modular libraries
+ zetaUtils : "com.github.zetaapps:utils:$versions.zetaUtilsVersion",
+ zetaEither : "com.github.zetaapps:either:$versions.zetaEitherVersion",
+ zetaListItemDivider : "com.github.zetaapps:List-Item-Divider:$versions.zetaListItemDividerVersion",
+ zetaHeaderAndFooterAdapters: "com.github.zetaapps:Header-Footer-Adapter:$versions.zetaHeaderAndFooterAdaptersVersion",
+ //endregion
+
+ //region animation
+ lottieAnimation : "com.airbnb.android:lottie:$versions.lottieAnimationVersion",
+ //endregion
+
+ //region DEVELOPER TOOLS
+ lynx : "com.github.pedrovgs:lynx:$versions.lynxVersion",
+ stetho : "com.facebook.stetho:stetho:$versions.stethoVersion",
+ timber : "com.jakewharton.timber:timber:$versions.timberVersion",
+ tinyDancer : "com.github.brianPlummer:tinydancer:$versions.tinyDancerVersion",
+ leakcanary : "com.squareup.leakcanary:leakcanary-android:$versions.leakcanaryVersion",
+ leakcanaryNoOp : "com.squareup.leakcanary:leakcanary-android-no-op:$versions.leakcanaryVersion",
+ //endregion
+
+ //region TESTING DEPENDENCIES
+ orgDotJson : "org.json:json:20160810",
+ junit : "junit:junit:$versions.junitVersion",
+ assertJ : "org.assertj:assertj-core:$versions.assertJVersion",
+ robolectric : "org.robolectric:robolectric:$versions.robolectricVersion",
+ equalsVerifier : "nl.jqno.equalsverifier:equalsverifier:$versions.equalsVerifierVersion",
+
+ mockitoCore : "org.mockito:mockito-core:$versions.mockitoVersion",
+ okHttpMockWebServer : "com.squareup.okhttp3:mockwebserver:$versions.okHttp3Version",
+ retrofitMock : "com.squareup.retrofit2:retrofit-mock:$versions.retrofitVersion",
+
+ supportTestRules : "com.android.support.test:rules:$versions.supportTestRunnerVersion",
+ supportTestRunner : "com.android.support.test:runner:$versions.supportTestRunnerVersion",
+
+ dexmaker : "com.google.dexmaker:dexmaker:$versions.dexmakerVersion",
+ dexmakerMockito : "com.google.dexmaker:dexmaker-mockito:$versions.dexmakerVersion",
+
+ espressoCore : "com.android.support.test.espresso:espresso-core:$versions.espressoVersion",
+ espressoContrib : "com.android.support.test.espresso:espresso-contrib:$versions.espressoVersion",
+ //endregion
+]
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..1d3591c
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,18 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+# Default value: -Xmx10248m -XX:MaxPermSize=256m
+# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..13372ae
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..a6c0fbe
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Mon Mar 06 12:18:37 IST 2017
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000..9d82f78
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..8a0b282
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/sample/.gitignore b/sample/.gitignore
new file mode 100644
index 0000000..905ab1c
--- /dev/null
+++ b/sample/.gitignore
@@ -0,0 +1,14 @@
+*.iml
+.gradle
+/local.properties
+/.idea/workspace.xml
+/.idea/libraries
+/.idea/vcs.xml
+/.idea/misc.xml
+.DS_Store
+/build
+/captures
+.idea/vcs.xml
+app/libs/
+/.idea
+
diff --git a/sample/build.gradle b/sample/build.gradle
new file mode 100644
index 0000000..46d32ac
--- /dev/null
+++ b/sample/build.gradle
@@ -0,0 +1,34 @@
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion versions.compileSdk
+ buildToolsVersion versions.buildTools
+
+ defaultConfig {
+ applicationId "com.myntra.coachmarks"
+ minSdkVersion versions.minSdk
+ targetSdkVersion versions.targetSdk
+ versionCode 1
+ versionName "0.0.1"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+
+ lintOptions {
+ abortOnError false
+ }
+}
+
+dependencies {
+ compile fileTree(dir: 'libs', include: ['*.jar'])
+ compile project(path: ':coachmarks')
+
+ compile libraries.supportAppCompat
+
+ testCompile 'junit:junit:4.12'
+}
diff --git a/sample/proguard-rules.pro b/sample/proguard-rules.pro
new file mode 100644
index 0000000..353bea2
--- /dev/null
+++ b/sample/proguard-rules.pro
@@ -0,0 +1,17 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /Users/z087205/Library/Android/sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
diff --git a/sample/src/androidTest/java/com/myntra/android/sample/ApplicationTest.java b/sample/src/androidTest/java/com/myntra/android/sample/ApplicationTest.java
new file mode 100644
index 0000000..445c153
--- /dev/null
+++ b/sample/src/androidTest/java/com/myntra/android/sample/ApplicationTest.java
@@ -0,0 +1,10 @@
+package com.myntra.android.sample;
+
+import android.app.Application;
+import android.test.ApplicationTestCase;
+
+public class ApplicationTest extends ApplicationTestCase {
+ public ApplicationTest() {
+ super(Application.class);
+ }
+}
\ No newline at end of file
diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..ea295c9
--- /dev/null
+++ b/sample/src/main/AndroidManifest.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample/src/main/assets/Whitney-Book-Bas.otf b/sample/src/main/assets/Whitney-Book-Bas.otf
new file mode 100644
index 0000000..544a883
Binary files /dev/null and b/sample/src/main/assets/Whitney-Book-Bas.otf differ
diff --git a/sample/src/main/assets/Whitney-Semibold-Bas.otf b/sample/src/main/assets/Whitney-Semibold-Bas.otf
new file mode 100644
index 0000000..e877dd7
Binary files /dev/null and b/sample/src/main/assets/Whitney-Semibold-Bas.otf differ
diff --git a/sample/src/main/java/com/myntra/sample/CoachMarksDemoActivity.java b/sample/src/main/java/com/myntra/sample/CoachMarksDemoActivity.java
new file mode 100644
index 0000000..957ee9e
--- /dev/null
+++ b/sample/src/main/java/com/myntra/sample/CoachMarksDemoActivity.java
@@ -0,0 +1,61 @@
+package com.myntra.sample;
+
+import android.graphics.Point;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+import android.widget.Button;
+
+import com.myntra.coachmarks.PopUpCoachMark;
+import com.myntra.coachmarks.builder.CoachMarkBuilder;
+import com.myntra.coachmarks.builder.ImageLayoutInformation;
+import com.myntra.coachmarks.builder.InfoForViewToMask;
+import com.myntra.coachmarks.common.DialogDismissButtonPosition;
+import com.myntra.coachmarks.common.PopUpPosition;
+
+import java.util.ArrayList;
+
+public class CoachMarksDemoActivity extends AppCompatActivity {
+
+ Button button;
+
+ private static final String FILE_NAME_MYNTRA_FONT_REGULAR = "Whitney-Book-Bas.otf";
+ private static final String FILE_NAME_MYNTRA_FONT_BOLD = "Whitney-Semibold-Bas.otf";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_coachmarks_demo);
+ button = (Button) findViewById(R.id.bt);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ button.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ showCoachMark();
+ }
+ });
+ }
+
+ private void showCoachMark() {
+ Point anchorTop = new Point(0, 800);
+ Point anchorBottom = new Point(200, 1000);
+ InfoForViewToMask infoForViewToMask = InfoForViewToMask.create(new Point(500, 500), 800, 400).build();
+ ArrayList infoForViewToMaskArrayList = new ArrayList<>(1);
+ infoForViewToMaskArrayList.add(infoForViewToMask);
+ ImageLayoutInformation imageLayoutInformation = ImageLayoutInformation.create(R.dimen.image_height, R.dimen.image_height).build();
+ CoachMarkBuilder testBuilder = CoachMarkBuilder.create(anchorTop, anchorBottom, R.string.coach_mark_pdp_collections)
+ .setImageLayoutInformation(imageLayoutInformation)
+ .setUserDesiredPopUpPositionWithRespectToView(PopUpPosition.RIGHT)
+ .setPopUpCoachMarkDismissButtonPosition(DialogDismissButtonPosition.RIGHT)
+ .setNotchPosition(.34).setInfoForViewToMaskList(infoForViewToMaskArrayList)
+ .setImageDrawableRes(R.drawable.similar_item_drawable)
+ .setFontStyleForCoachMarkText(FILE_NAME_MYNTRA_FONT_REGULAR)
+ .setFontStyleForDismissButton(FILE_NAME_MYNTRA_FONT_BOLD).build();
+ PopUpCoachMark popUpCoachMark = PopUpCoachMark.newInstance(testBuilder);
+ popUpCoachMark.show(getSupportFragmentManager(), "Test");
+ }
+}
diff --git a/sample/src/main/res/drawable/similar_item_drawable.xml b/sample/src/main/res/drawable/similar_item_drawable.xml
new file mode 100644
index 0000000..5240017
--- /dev/null
+++ b/sample/src/main/res/drawable/similar_item_drawable.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
diff --git a/sample/src/main/res/layout/activity_coachmarks_demo.xml b/sample/src/main/res/layout/activity_coachmarks_demo.xml
new file mode 100644
index 0000000..7c1e56f
--- /dev/null
+++ b/sample/src/main/res/layout/activity_coachmarks_demo.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
diff --git a/sample/src/main/res/mipmap-hdpi/ic_launcher.png b/sample/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..cde69bc
Binary files /dev/null and b/sample/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/sample/src/main/res/mipmap-hdpi/ic_wishlist.png b/sample/src/main/res/mipmap-hdpi/ic_wishlist.png
new file mode 100755
index 0000000..421f5ef
Binary files /dev/null and b/sample/src/main/res/mipmap-hdpi/ic_wishlist.png differ
diff --git a/sample/src/main/res/mipmap-mdpi/ic_launcher.png b/sample/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c133a0c
Binary files /dev/null and b/sample/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/sample/src/main/res/mipmap-mdpi/ic_wishlist.png b/sample/src/main/res/mipmap-mdpi/ic_wishlist.png
new file mode 100755
index 0000000..c730d37
Binary files /dev/null and b/sample/src/main/res/mipmap-mdpi/ic_wishlist.png differ
diff --git a/sample/src/main/res/mipmap-xhdpi/ic_launcher.png b/sample/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..bfa42f0
Binary files /dev/null and b/sample/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/sample/src/main/res/mipmap-xhdpi/ic_wishlist.png b/sample/src/main/res/mipmap-xhdpi/ic_wishlist.png
new file mode 100755
index 0000000..c165c1e
Binary files /dev/null and b/sample/src/main/res/mipmap-xhdpi/ic_wishlist.png differ
diff --git a/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png b/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..324e72c
Binary files /dev/null and b/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..aee44e1
Binary files /dev/null and b/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/sample/src/main/res/values-w820dp/dimens.xml b/sample/src/main/res/values-w820dp/dimens.xml
new file mode 100644
index 0000000..63fc816
--- /dev/null
+++ b/sample/src/main/res/values-w820dp/dimens.xml
@@ -0,0 +1,6 @@
+
+
+ 64dp
+
diff --git a/sample/src/main/res/values/colors.xml b/sample/src/main/res/values/colors.xml
new file mode 100644
index 0000000..6db5eb9
--- /dev/null
+++ b/sample/src/main/res/values/colors.xml
@@ -0,0 +1,8 @@
+
+
+ #3F51B5
+ #303F9F
+ #FF4081
+ #ff3e6c
+ #3dffffff
+
diff --git a/sample/src/main/res/values/dimens.xml b/sample/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..aa52cf5
--- /dev/null
+++ b/sample/src/main/res/values/dimens.xml
@@ -0,0 +1,7 @@
+
+
+ 16dp
+ 16dp
+ 40dp
+ -20dp
+
diff --git a/sample/src/main/res/values/strings.xml b/sample/src/main/res/values/strings.xml
new file mode 100644
index 0000000..9470ca8
--- /dev/null
+++ b/sample/src/main/res/values/strings.xml
@@ -0,0 +1,4 @@
+
+ CoachMarks
+ Long press to quickly save item to wishlist
+
diff --git a/sample/src/main/res/values/styles.xml b/sample/src/main/res/values/styles.xml
new file mode 100644
index 0000000..5885930
--- /dev/null
+++ b/sample/src/main/res/values/styles.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
diff --git a/sample/src/test/java/com/myntra/android/sample/CoachMarkUnitTest.java b/sample/src/test/java/com/myntra/android/sample/CoachMarkUnitTest.java
new file mode 100644
index 0000000..53aaf01
--- /dev/null
+++ b/sample/src/test/java/com/myntra/android/sample/CoachMarkUnitTest.java
@@ -0,0 +1,12 @@
+package com.myntra.android.sample;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class CoachMarkUnitTest {
+ @Test
+ public void addition_isCorrect() throws Exception {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..1ba1c11
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1 @@
+include ':sample', ':coachmarks'