├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── README_pushing_to_maven.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── tourguide │ │ └── tourguidedemo │ │ ├── ApplicationTest.kt │ │ ├── BasicActivityCrashTest.kt │ │ └── ToolTilMeasureTest.kt │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── tourguide │ │ ├── instrumentation │ │ └── test │ │ │ └── ToolTipMeasureTestActivity.kt │ │ └── tourguidedemo │ │ ├── AdjustPaddingOverlayActivity.kt │ │ ├── BasicActivity.kt │ │ ├── ManualSequenceActivity.kt │ │ ├── MemoryLeakTestActivity.kt │ │ ├── MultipleToolTipActivity.kt │ │ ├── MyApplication.kt │ │ ├── NavDrawerActivity.kt │ │ ├── NoOverlayActivity.kt │ │ ├── NoPointerActivity.kt │ │ ├── NoPointerNoToolTipActivity.kt │ │ ├── OverlayCustomizationActivity.kt │ │ ├── RecyclerViewActivity.kt │ │ ├── RoundedRectangleOverlayActivity.kt │ │ ├── ToolTipCustomizationActivity.kt │ │ ├── ToolTipGravityActivity.kt │ │ ├── ToolbarActivity.kt │ │ ├── main │ │ ├── MainActivity.kt │ │ └── MainAdapter.kt │ │ └── recyclerview │ │ └── RecyclerViewAdapter.kt │ └── res │ ├── drawable-hdpi │ └── tour_guide_icon.png │ ├── drawable-mdpi │ └── tour_guide_icon.png │ ├── drawable-xhdpi │ └── tour_guide_icon.png │ ├── drawable-xxhdpi │ └── tour_guide_icon.png │ ├── drawable │ └── toolbar_drop_shadow.xml │ ├── layout │ ├── activity_basic.xml │ ├── activity_customization.xml │ ├── activity_in_sequence.xml │ ├── activity_multiple_tooltip.xml │ ├── activity_nav_drawer.xml │ ├── activity_overlay_customization.xml │ ├── activity_recycler_view.xml │ ├── activity_toolbar.xml │ ├── activity_tooltip_gravity_i.xml │ ├── activity_tooltip_gravity_ii.xml │ ├── activity_tooltip_gravity_iii.xml │ ├── activity_tooltip_gravity_iv.xml │ ├── activity_tour_guide_demo_main.xml │ ├── nav_drawer_header.xml │ ├── row.xml │ ├── row_recycler_view.xml │ └── sequence_dialog.xml │ ├── menu │ └── menu_demo_main.xml │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ ├── styles.xml │ └── themes.xml ├── build.gradle ├── gradle-mvn-push.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle ├── tourguide ├── .gitignore ├── build.gradle ├── gradle.properties ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── tourguide │ │ └── tourguide │ │ └── ApplicationTest.kt │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── tourguide │ │ └── tourguide │ │ ├── FrameLayoutWithHole.kt │ │ ├── Overlay.kt │ │ ├── Pointer.kt │ │ ├── ToolTip.kt │ │ ├── TourGuide.kt │ │ └── util │ │ ├── MotionEventExtension.kt │ │ ├── StandardExtension.kt │ │ └── ViewExtension.kt │ └── res │ ├── drawable-xhdpi │ └── tourguide_drop_shadow.9.png │ ├── drawable │ └── tourguide_shadow_upward.xml │ ├── layout │ └── tourguide_tooltip.xml │ └── values │ └── colors.xml └── update_version.rb /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea/workspace.xml 4 | /.idea/libraries 5 | .DS_Store 6 | /build 7 | .idea/ 8 | *.iml 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: android 2 | jdk: oraclejdk8 3 | env: 4 | matrix: 5 | - ANDROID_API=26 ANDROID_ABI=armeabi-v7a 6 | android: 7 | components: 8 | # Uncomment the lines below if you want to 9 | # use the latest revision of Android SDK Tools 10 | - tools 11 | - platform-tools 12 | - tools 13 | 14 | # The BuildTools version used by your project 15 | - build-tools-26.0.2 16 | 17 | # The SDK version used to compile your project 18 | - android-26 19 | - android-22 20 | - extra-android-support 21 | - extra-android-m2repository 22 | # Additional components 23 | #- extra-google-google_play_services 24 | #- extra-google-m2repository 25 | #- extra-android-m2repository 26 | #- addon-google_apis-google-19 27 | 28 | # Specify at least one system image, 29 | # if you need to run emulator(s) during your tests 30 | - sys-img-armeabi-v7a-android-22 31 | #- sys-img-x86-android-17 32 | licenses: 33 | - 'android-sdk-preview-license-.+' 34 | - 'android-sdk-license-.+' 35 | - 'google-gdk-license-.+' 36 | before_script: 37 | # Create and start emulator 38 | - echo no | android create avd --force -n test -t android-22 --abi armeabi-v7a 39 | - emulator -avd test -no-skin -no-audio -no-window & 40 | - android-wait-for-emulator 41 | - adb shell input keyevent 82 & 42 | 43 | script: ./gradlew build connectedCheck 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) [2015] [Tan Jun Rong] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](https://img.shields.io/badge/Kotlin-1.2.10-orange.svg) ![](https://api.travis-ci.org/worker8/TourGuide.svg?branch=master) ![](https://camo.githubusercontent.com/cf76db379873b010c163f9cf1b5de4f5730b5a67/68747470733a2f2f6261646765732e66726170736f66742e636f6d2f6f732f6d69742f6d69742e7376673f763d313032) 2 | 3 | # TourGuide 4 | TourGuide is an Android library. It lets you add pointer, overlay and tooltip easily, guiding users on how to use your app. Refer to the example below(this is a trivial example for demo purpose): 5 | 6 | # Documentation 7 | Refer to this :point_down: 8 | 9 | http://worker8.github.io/TourGuide/ 10 | 11 | # License 12 |
13 | 14 | click to reveal License 15 | 16 | 17 | The MIT License (MIT) 18 | 19 | Copyright (c) 2016 Tan Jun Rong 20 | 21 | Permission is hereby granted, free of charge, to any person obtaining a copy 22 | of this software and associated documentation files (the "Software"), to deal 23 | in the Software without restriction, including without limitation the rights 24 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 25 | copies of the Software, and to permit persons to whom the Software is 26 | furnished to do so, subject to the following conditions: 27 | 28 | The above copyright notice and this permission notice shall be included in all 29 | copies or substantial portions of the Software. 30 | 31 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 32 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 33 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 34 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 35 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 36 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 37 | SOFTWARE. 38 | 39 | 40 |
41 | -------------------------------------------------------------------------------- /README_pushing_to_maven.md: -------------------------------------------------------------------------------- 1 | update versions 2 | 3 | 1. run `ruby update_version.rb` 4 | - this will increase the versionName & versionCode in gradle.properties 5 | 2. update gh-pages branch install guide version 6 | 7 | 4. git push origin master 8 | 5. ./gradlew clean build uploadArchives 9 | 6. update git tag, convention: git tag -a v1.0.11 -m "VERSION_CODE=12, VERSION_NAME=1.0.11-SNAPSHOT" 10 | 7. git push --tags 11 | 12 | reference: 13 | https://github.com/chrisbanes/gradle-mvn-push 14 | 15 | update playstore steps: 16 | 1. ./production.sh 17 | 2. upload apk 18 | 3. update commit hash in playstore readme 19 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'kotlin-android-extensions' 4 | 5 | repositories { 6 | mavenCentral() 7 | maven() { 8 | url "https://oss.sonatype.org/content/repositories/snapshots" 9 | } 10 | } 11 | 12 | Properties getGradleProperties() { 13 | def gradlePropsFile = file('../gradle.properties') 14 | def Properties gradleProps = new Properties() 15 | if (gradlePropsFile.canRead()) { 16 | gradleProps.load(new FileInputStream(gradlePropsFile)) 17 | println gradleProps['VERSION_CODE'] 18 | println gradleProps['VERSION_NAME'] 19 | } else { 20 | throw new GradleException("Could not read gradle.properties!") 21 | } 22 | gradleProps; 23 | } 24 | 25 | android { 26 | compileSdkVersion compileSdkVersionNum 27 | buildToolsVersion buildToolVersionNum 28 | def gradleProps = getGradleProperties() 29 | defaultConfig { 30 | applicationId "tourguide.tourguide" 31 | minSdkVersion minSdkVersionNum 32 | targetSdkVersion targetSdkVersionNum 33 | versionCode gradleProps['VERSION_CODE'].toInteger() 34 | versionName gradleProps['VERSION_NAME'] 35 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 36 | } 37 | 38 | buildTypes { 39 | release { 40 | minifyEnabled false 41 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 42 | } 43 | } 44 | lintOptions { 45 | abortOnError false 46 | } 47 | packagingOptions { 48 | exclude 'LICENSE.txt' 49 | } 50 | } 51 | 52 | task sourcesJar(type: Jar) { 53 | from android.sourceSets.main.java.srcDirs 54 | classifier = 'sources' 55 | } 56 | 57 | artifacts { 58 | archives sourcesJar 59 | } 60 | 61 | dependencies { 62 | implementation fileTree(dir: 'libs', include: ['*.jar']) 63 | implementation "com.android.support:appcompat-v7:$supportVersion" 64 | implementation "com.android.support:design:$supportVersion" 65 | implementation project(':tourguide') 66 | 67 | /* this is for debugging memory leak: https://github.com/square/leakcanary */ 68 | debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.3.1' 69 | releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1' 70 | 71 | androidTestImplementation('com.android.support.test.espresso:espresso-core:3.0.1') { 72 | exclude group: 'com.android.support', module: 'support-annotations' 73 | } 74 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 75 | 76 | 77 | } 78 | 79 | task print_git_tag_command << { 80 | def gradleProps = getGradleProperties() 81 | println "git tag -a v" + gradleProps['VERSION_NAME'] + " -m \"VERSION_CODE=" + gradleProps['VERSION_CODE'] + ", VERSION_NAME=" + gradleProps['VERSION_NAME'] + "\"" 82 | println "git push --tags" 83 | } 84 | 85 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/tanjunrong/adt-bundle-mac-x86_64-20140702/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/tourguide/tourguidedemo/ApplicationTest.kt: -------------------------------------------------------------------------------- 1 | package tourguide.tourguidedemo 2 | 3 | import android.app.Application 4 | import android.test.ApplicationTestCase 5 | 6 | /** 7 | * [Testing Fundamentals](http://d.android.com/tools/testing/testing_android.html) 8 | */ 9 | class ApplicationTest : ApplicationTestCase(Application::class.java) -------------------------------------------------------------------------------- /app/src/androidTest/java/tourguide/tourguidedemo/BasicActivityCrashTest.kt: -------------------------------------------------------------------------------- 1 | package tourguide.tourguidedemo 2 | 3 | import android.support.test.espresso.Espresso.onView 4 | import android.support.test.espresso.action.ViewActions.click 5 | import android.support.test.espresso.matcher.ViewMatchers.withId 6 | import android.support.test.rule.ActivityTestRule 7 | import org.hamcrest.Matchers.allOf 8 | import org.junit.Assert 9 | import org.junit.Rule 10 | import org.junit.Test 11 | 12 | class BasicActivityCrashTest { 13 | @Rule @JvmField 14 | var rule: ActivityTestRule = ActivityTestRule(BasicActivity::class.java) 15 | 16 | @Test 17 | fun testNoCrash() { 18 | onView(allOf(withId(R.id.button1))).perform(click()) 19 | Assert.assertTrue("There is no crash :)", true) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/tourguide/tourguidedemo/ToolTilMeasureTest.kt: -------------------------------------------------------------------------------- 1 | package tourguide.tourguidedemo 2 | 3 | import android.app.Activity 4 | import android.graphics.Point 5 | import android.test.ActivityInstrumentationTestCase2 6 | import android.view.View 7 | import org.junit.Assert 8 | import tourguide.instrumentation.test.ToolTipMeasureTestActivity 9 | 10 | class ToolTilMeasureTest : ActivityInstrumentationTestCase2(ToolTipMeasureTestActivity::class.java) { 11 | private var mActivity: ToolTipMeasureTestActivity? = null 12 | private var mToolTip: View? = null 13 | 14 | @Throws(Exception::class) 15 | override fun setUp() { 16 | super.setUp() 17 | 18 | // Starts the activity under test using the default Intent with: 19 | // action = {@link Intent#ACTION_MAIN} 20 | // flags = {@link Intent#FLAG_ACTIVITY_NEW_TASK} 21 | // All other fields are null or empty. 22 | mActivity = activity 23 | mToolTip = mActivity!!.tourGuide.toolTipView 24 | } 25 | 26 | fun testNoCrash() { 27 | val isOutOfLeftBound = mToolTip!!.x < 0 28 | val isOutOfRightBound = mToolTip!!.x + mToolTip!!.width > getScreenWidth(mActivity!!) 29 | Assert.assertFalse("x of ToolTip is out of screen boundary", isOutOfLeftBound || isOutOfRightBound) 30 | 31 | val isOutOfTopBound = mToolTip!!.y < 0 32 | val isOutOfBottomBound = mToolTip!!.y + mToolTip!!.height > getScreenHeight(mActivity!!) 33 | Assert.assertFalse("y of ToolTip is out of screen boundary", isOutOfTopBound || isOutOfBottomBound) 34 | } 35 | 36 | private fun getScreenWidth(activity: Activity): Int { 37 | val display = activity.windowManager.defaultDisplay 38 | val size = Point() 39 | display.getSize(size) 40 | return size.x 41 | } 42 | 43 | private fun getScreenHeight(activity: Activity): Int { 44 | val display = activity.windowManager.defaultDisplay 45 | val size = Point() 46 | display.getSize(size) 47 | return size.y 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 15 | 18 | 21 | 24 | 27 | 30 | 33 | 36 | 39 | 42 | 45 | 49 | 52 | 55 | 59 | 62 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /app/src/main/java/tourguide/instrumentation/test/ToolTipMeasureTestActivity.kt: -------------------------------------------------------------------------------- 1 | package tourguide.instrumentation.test 2 | 3 | import android.graphics.Color 4 | import android.os.Bundle 5 | import android.support.v7.app.AppCompatActivity 6 | import android.view.Gravity 7 | import kotlinx.android.synthetic.main.activity_tooltip_gravity_i.* 8 | import tourguide.tourguide.Overlay 9 | import tourguide.tourguide.Pointer 10 | import tourguide.tourguide.TourGuide 11 | import tourguide.tourguidedemo.R 12 | 13 | 14 | class ToolTipMeasureTestActivity : AppCompatActivity() { 15 | lateinit var tourGuide: TourGuide 16 | 17 | override fun onCreate(savedInstanceState: Bundle?) { 18 | /* Get parameters from main activity */ 19 | val intent = intent 20 | val tooltipNumber = intent.getIntExtra(TOOLTIP_NUM, 1) 21 | 22 | super.onCreate(savedInstanceState) 23 | val gravity = when (tooltipNumber) { 24 | 1 -> { 25 | setContentView(R.layout.activity_tooltip_gravity_i) 26 | Gravity.RIGHT or Gravity.BOTTOM 27 | } 28 | 2 -> { 29 | setContentView(R.layout.activity_tooltip_gravity_ii) 30 | Gravity.LEFT or Gravity.BOTTOM 31 | } 32 | 3 -> { 33 | setContentView(R.layout.activity_tooltip_gravity_iii) 34 | Gravity.LEFT or Gravity.TOP 35 | } 36 | else -> { 37 | setContentView(R.layout.activity_tooltip_gravity_iv) 38 | Gravity.RIGHT or Gravity.TOP 39 | } 40 | } 41 | 42 | tourGuide = TourGuide.create(this) { 43 | pointer { Pointer() } 44 | overlay { Overlay() } 45 | toolTip { 46 | title { "Welcome!" } 47 | description { "This is a really really long title....This is a really really long title....This is a really really long title....This is a really really long title....This is a really really long title....This is a really really long title....This is a really really long title...." } 48 | backgroundColor { Color.parseColor("#2980b9") } 49 | textColor { Color.parseColor("#FFFFFF") } 50 | gravity { gravity } 51 | shadow { true } 52 | } 53 | }.playOn(button) 54 | 55 | button.setOnClickListener { tourGuide.cleanUp() } 56 | } 57 | 58 | companion object { 59 | const val TOOLTIP_NUM = "tooltip_num" 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/java/tourguide/tourguidedemo/AdjustPaddingOverlayActivity.kt: -------------------------------------------------------------------------------- 1 | package tourguide.tourguidedemo 2 | 3 | import android.graphics.Color 4 | import android.os.Bundle 5 | import android.support.v7.app.AppCompatActivity 6 | import android.text.Editable 7 | import android.text.TextUtils 8 | import android.text.TextWatcher 9 | import android.view.View 10 | import kotlinx.android.synthetic.main.activity_overlay_customization.* 11 | import tourguide.tourguide.Overlay 12 | import tourguide.tourguide.TourGuide 13 | 14 | 15 | class AdjustPaddingOverlayActivity : AppCompatActivity() { 16 | lateinit var tourGuide: TourGuide 17 | override fun onCreate(savedInstanceState: Bundle?) { 18 | super.onCreate(savedInstanceState) 19 | setContentView(R.layout.activity_overlay_customization) 20 | tourGuide = TourGuide 21 | .create(this) { 22 | toolTip { 23 | title { "Hello!" } 24 | description { String.format("Current OVERLAY Padding: %s", paddingEditText.text.toString()) } 25 | } 26 | overlay { 27 | disableClick { false } 28 | disableClickThroughHole { false } 29 | style { Overlay.Style.ROUNDED_RECTANGLE } 30 | holePadding { Integer.valueOf(paddingEditText.text.toString()) } 31 | backgroundColor { Color.parseColor("#AAFF0000") } 32 | onClickListener { View.OnClickListener { tourGuide.cleanUp() } } 33 | } 34 | } 35 | .apply { playOn(button) } 36 | 37 | paddingEditText.setText(10.toString()) 38 | textInputLayout.visibility = View.VISIBLE 39 | 40 | nextButton.visibility = View.GONE 41 | 42 | button.setOnClickListener { 43 | tourGuide.cleanUp() 44 | tourGuide.playOn(button) 45 | } 46 | button.text = " show " 47 | 48 | paddingEditText.addTextChangedListener(object : TextWatcher { 49 | override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) { 50 | 51 | } 52 | 53 | override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) { 54 | tourGuide.overlay?.setHolePadding(if (charSequence.length > 0 && TextUtils.isDigitsOnly(charSequence)) Integer.valueOf(charSequence.toString()) else 10) 55 | tourGuide.toolTip?.setDescription(String.format("Current Overlay Padding: %s", charSequence)) 56 | } 57 | 58 | override fun afterTextChanged(editable: Editable) { 59 | } 60 | }) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/tourguide/tourguidedemo/BasicActivity.kt: -------------------------------------------------------------------------------- 1 | package tourguide.tourguidedemo 2 | 3 | import android.graphics.Color 4 | import android.os.Bundle 5 | import android.support.v7.app.AppCompatActivity 6 | import android.view.Gravity 7 | import kotlinx.android.synthetic.main.activity_basic.* 8 | import tourguide.tourguide.TourGuide 9 | 10 | class BasicActivity : AppCompatActivity() { 11 | override fun onCreate(savedInstanceState: Bundle?) { 12 | /* Get parameters from main activity */ 13 | val colorDemo = intent.getBooleanExtra(COLOR_DEMO, false) 14 | val gravityDemo = intent.getBooleanExtra(GRAVITY_DEMO, false) 15 | 16 | super.onCreate(savedInstanceState) 17 | setContentView(R.layout.activity_basic) 18 | 19 | // the return handler is used to manipulate the cleanup of all the tutorial elements 20 | val tourGuide = TourGuide.create(this) { 21 | technique = TourGuide.Technique.CLICK 22 | pointer { 23 | color { 24 | if (colorDemo) { 25 | Color.RED 26 | } else { 27 | Color.WHITE 28 | } 29 | } 30 | gravity { 31 | if (gravityDemo) { 32 | Gravity.BOTTOM or Gravity.RIGHT 33 | } else { 34 | Gravity.CENTER 35 | } 36 | } 37 | } 38 | toolTip { 39 | title { "Welcome!" } 40 | description { "Click on Get Started to begin..." } 41 | } 42 | overlay { 43 | backgroundColor { Color.parseColor("#66FF0000") } 44 | } 45 | } 46 | val handler = tourGuide playOn button1 47 | 48 | button1.setOnClickListener { handler.cleanUp() } 49 | button2.setOnClickListener { handler.playOn(button1) } 50 | } 51 | 52 | companion object { 53 | const val COLOR_DEMO = "color_demo" 54 | const val GRAVITY_DEMO = "gravity_demo" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/tourguide/tourguidedemo/ManualSequenceActivity.kt: -------------------------------------------------------------------------------- 1 | package tourguide.tourguidedemo 2 | 3 | import android.os.Bundle 4 | import android.support.v7.app.AppCompatActivity 5 | import android.view.Gravity 6 | import android.view.animation.AlphaAnimation 7 | import kotlinx.android.synthetic.main.activity_in_sequence.* 8 | import tourguide.tourguide.Pointer 9 | import tourguide.tourguide.TourGuide 10 | 11 | /** 12 | * InSequenceActivity demonstrates how to use TourGuide in sequence one after another 13 | */ 14 | class ManualSequenceActivity : AppCompatActivity() { 15 | lateinit var tourGuide: TourGuide 16 | 17 | override fun onCreate(savedInstanceState: Bundle?) { 18 | super.onCreate(savedInstanceState) 19 | setContentView(R.layout.activity_in_sequence) 20 | 21 | /* setup enter and exit animation */ 22 | val enterAnimation = AlphaAnimation(0f, 1f) 23 | .apply { 24 | duration = 600 25 | fillAfter = true 26 | } 27 | 28 | 29 | val exitAnimation = AlphaAnimation(1f, 0f) 30 | .apply { 31 | duration = 600 32 | fillAfter = true 33 | } 34 | 35 | /* initialize TourGuide without playOn() */ 36 | tourGuide = TourGuide.create(this) { 37 | pointer { Pointer() } 38 | toolTip { 39 | title { "Hey!" } 40 | description { "I'm the top fellow" } 41 | gravity { Gravity.RIGHT } 42 | } 43 | overlay { 44 | setEnterAnimation(enterAnimation) 45 | setExitAnimation(exitAnimation) 46 | } 47 | } 48 | 49 | /* setup 1st button, when clicked, cleanUp() and re-run TourGuide on button2 */ 50 | button.setOnClickListener { 51 | tourGuide.apply { 52 | cleanUp() 53 | toolTip { 54 | title { "Hey there!" } 55 | description { "Just the middle man" } 56 | gravity { Gravity.BOTTOM or Gravity.LEFT } 57 | } 58 | }.playOn(button2) 59 | } 60 | 61 | /* setup 2nd button, when clicked, cleanUp() and re-run TourGuide on button3 */ 62 | button2.setOnClickListener { 63 | tourGuide.apply { 64 | cleanUp() 65 | toolTip { 66 | title { "Hey..." } 67 | description { "It's time to say goodbye" } 68 | gravity { Gravity.TOP or Gravity.RIGHT } 69 | } 70 | }.playOn(button3) 71 | } 72 | 73 | /* setup 3rd button, when clicked, run cleanUp() */ 74 | button3.setOnClickListener { tourGuide.cleanUp() } 75 | 76 | tourGuide.playOn(button) 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /app/src/main/java/tourguide/tourguidedemo/MemoryLeakTestActivity.kt: -------------------------------------------------------------------------------- 1 | package tourguide.tourguidedemo 2 | 3 | import android.os.Bundle 4 | import android.support.v7.app.AppCompatActivity 5 | import kotlinx.android.synthetic.main.activity_basic.* 6 | import tourguide.tourguide.Overlay 7 | import tourguide.tourguide.Pointer 8 | import tourguide.tourguide.TourGuide 9 | 10 | /** 11 | * This activity is used for testing memory, it serves no demo purpose, hence it's not listed in TourGuideDemoMain activity (it's commented out) 12 | * To test this: 13 | * 1. uncomment MemoryLeakTestActivity in TourGuideDemoMain.java 14 | * 2. Then launch MemoryLeakTestActivity and click back, launch MemoryLeakTestActivity and click back, repeat many times 15 | * 3. Then look at the memory usage, also check if LeakCanary freezes the screen and log a memory heap dump 16 | * 4. To force a memory leak, comment 'onDetachedFromWindow()' method in FrameLayoutWithHole 17 | * TODO: this should be included as a test, rather than being a commented activity 18 | */ 19 | class MemoryLeakTestActivity : AppCompatActivity() { 20 | lateinit var tourGuide: TourGuide 21 | override fun onCreate(savedInstanceState: Bundle?) { 22 | super.onCreate(savedInstanceState) 23 | setContentView(R.layout.activity_basic) 24 | 25 | tourGuide = TourGuide.create(this) { 26 | pointer { Pointer() } 27 | overlay { Overlay() } 28 | toolTip { 29 | title { "Hey!" } 30 | description { "Let's hope that there's no memory leak..." } 31 | } 32 | }.playOn(button1) 33 | 34 | button1.setOnClickListener { tourGuide.cleanUp() } 35 | } 36 | 37 | public override fun onDestroy() { 38 | super.onDestroy() 39 | MyApplication.getRefWatcher(this)?.also { _refWatcher -> 40 | _refWatcher.watch(this) 41 | _refWatcher.watch(tourGuide) 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/tourguide/tourguidedemo/MultipleToolTipActivity.kt: -------------------------------------------------------------------------------- 1 | package tourguide.tourguidedemo 2 | 3 | import android.os.Bundle 4 | import android.support.v7.app.AppCompatActivity 5 | import android.view.Gravity 6 | import kotlinx.android.synthetic.main.activity_multiple_tooltip.* 7 | import tourguide.tourguide.Pointer 8 | import tourguide.tourguide.TourGuide 9 | 10 | /** 11 | * Note that currently multiple Overlay doesn't work well, but multiple ToolTip is working fine 12 | * Therefore, if you want to use multiple ToolTip, please switch off the Overlay by .setOverlay(null) 13 | */ 14 | class MultipleToolTipActivity : AppCompatActivity() { 15 | 16 | override fun onCreate(savedInstanceState: Bundle?) { 17 | super.onCreate(savedInstanceState) 18 | 19 | setContentView(R.layout.activity_multiple_tooltip) 20 | 21 | // the return handler is used to manipulate the cleanup of all the tutorial elements 22 | val tourGuide = TourGuide.create(this) { 23 | pointer { Pointer() } 24 | toolTip { 25 | title { "Hey!" } 26 | description { "I'm the top guy" } 27 | gravity { Gravity.RIGHT } 28 | } 29 | }.playOn(button) 30 | 31 | val tourGuide2 = TourGuide.create(this) { 32 | pointer { Pointer() } 33 | toolTip { 34 | title { "Hey!" } 35 | description { "I'm the bottom guy" } 36 | gravity { Gravity.TOP or Gravity.LEFT } 37 | } 38 | }.playOn(button2) 39 | 40 | button.setOnClickListener { tourGuide.cleanUp() } 41 | button2.setOnClickListener { tourGuide2.cleanUp() } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/src/main/java/tourguide/tourguidedemo/MyApplication.kt: -------------------------------------------------------------------------------- 1 | package tourguide.tourguidedemo 2 | 3 | import android.app.Application 4 | import android.content.Context 5 | 6 | import com.squareup.leakcanary.LeakCanary 7 | import com.squareup.leakcanary.RefWatcher 8 | 9 | class MyApplication : Application() { 10 | private var _refWatcher: RefWatcher? = null 11 | 12 | override fun onCreate() { 13 | super.onCreate() 14 | /* This is for checking memory leak: https://github.com/square/leakcanary */ 15 | _refWatcher = LeakCanary.install(this) 16 | } 17 | 18 | companion object { 19 | 20 | fun getRefWatcher(context: Context): RefWatcher? { 21 | val application = context.applicationContext as MyApplication 22 | return application._refWatcher 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/tourguide/tourguidedemo/NavDrawerActivity.kt: -------------------------------------------------------------------------------- 1 | package tourguide.tourguidedemo 2 | 3 | import android.graphics.Color 4 | import android.os.Bundle 5 | import android.support.v7.app.ActionBarDrawerToggle 6 | import android.support.v7.app.AppCompatActivity 7 | import android.view.Gravity 8 | import android.view.View 9 | import android.view.ViewTreeObserver 10 | import kotlinx.android.synthetic.main.activity_nav_drawer.* 11 | import tourguide.tourguide.TourGuide 12 | 13 | class NavDrawerActivity : AppCompatActivity() { 14 | 15 | override fun onCreate(savedInstanceState: Bundle?) { 16 | super.onCreate(savedInstanceState) 17 | setContentView(R.layout.activity_nav_drawer) 18 | 19 | /* setup toolbar */ 20 | setSupportActionBar(toolbar.apply { title = "Nav Drawer Example" }) 21 | supportActionBar?.apply { 22 | setDisplayHomeAsUpEnabled(true) 23 | setHomeButtonEnabled(true) 24 | setDisplayShowTitleEnabled(false) 25 | } 26 | 27 | val tourGuide = TourGuide.create(this) { 28 | pointer { } 29 | overlay { backgroundColor { Color.parseColor("#66FF0000") } } 30 | toolTip { 31 | title { "" } 32 | description { "hello world" } 33 | } 34 | } 35 | 36 | val drawerToggle = object : ActionBarDrawerToggle( 37 | this, drawerLayout, toolbar, R.string.drawer_open_string, R.string.drawer_close_string) { 38 | override fun onDrawerOpened(drawerView: View?) { 39 | super.onDrawerOpened(drawerView) 40 | /* We need call playOn only after the drawer is opened, 41 | so that TourGuide knows the updated location of the targetted view */ 42 | tourGuide.playOn(textView1) 43 | } 44 | } 45 | drawerLayout.setDrawerListener(drawerToggle) 46 | drawerToggle.syncState() 47 | 48 | /* setup clean up code */ 49 | textView1.setOnClickListener { 50 | tourGuide.cleanUp() 51 | drawerLayout.closeDrawers() 52 | } 53 | 54 | textView1.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { 55 | override fun onGlobalLayout() { 56 | textView1.viewTreeObserver.removeGlobalOnLayoutListener(this)// make sure this only run once 57 | drawerLayout.openDrawer(Gravity.LEFT) 58 | } 59 | }) 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/tourguide/tourguidedemo/NoOverlayActivity.kt: -------------------------------------------------------------------------------- 1 | package tourguide.tourguidedemo 2 | 3 | import android.os.Bundle 4 | import android.support.v7.app.AppCompatActivity 5 | import kotlinx.android.synthetic.main.activity_basic.* 6 | import tourguide.tourguide.Pointer 7 | import tourguide.tourguide.ToolTip 8 | import tourguide.tourguide.TourGuide 9 | 10 | 11 | class NoOverlayActivity : AppCompatActivity() { 12 | 13 | override fun onCreate(savedInstanceState: Bundle?) { 14 | super.onCreate(savedInstanceState) 15 | setContentView(R.layout.activity_basic) 16 | 17 | val tourGuide = TourGuide.init(this).with(TourGuide.Technique.CLICK) 18 | .setPointer(Pointer()) // set pointer to null 19 | .setToolTip(ToolTip().setTitle("Welcome :)").setDescription("Have a nice and fun day!")) 20 | .playOn(button1) 21 | 22 | button1.setOnClickListener { tourGuide.cleanUp() } 23 | button2.setOnClickListener { tourGuide.playOn(button1) } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/tourguide/tourguidedemo/NoPointerActivity.kt: -------------------------------------------------------------------------------- 1 | package tourguide.tourguidedemo 2 | 3 | import android.os.Bundle 4 | import android.support.v7.app.AppCompatActivity 5 | import android.view.View 6 | import kotlinx.android.synthetic.main.activity_basic.* 7 | import tourguide.tourguide.TourGuide 8 | 9 | 10 | class NoPointerActivity : AppCompatActivity() { 11 | lateinit var tourGuide: TourGuide 12 | override fun onCreate(savedInstanceState: Bundle?) { 13 | /* Get parameters from main activity */ 14 | super.onCreate(savedInstanceState) 15 | setContentView(R.layout.activity_basic) 16 | 17 | button1.text = "Purchase" 18 | 19 | tourGuide = TourGuide.create(this) { 20 | toolTip { 21 | title { "Expensive Item" } 22 | description { "Click 'purchase' only when you are ready\nClick on the anywhere to dismiss" } 23 | } 24 | overlay { 25 | disableClickThroughHole { true } 26 | onClickListener { View.OnClickListener { tourGuide.cleanUp() } } 27 | } 28 | }.playOn(button1) 29 | 30 | button2.setOnClickListener { tourGuide.playOn(button1) } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/tourguide/tourguidedemo/NoPointerNoToolTipActivity.kt: -------------------------------------------------------------------------------- 1 | package tourguide.tourguidedemo 2 | 3 | import android.os.Bundle 4 | import android.support.v7.app.AppCompatActivity 5 | import kotlinx.android.synthetic.main.activity_basic.* 6 | import tourguide.tourguide.TourGuide 7 | 8 | 9 | class NoPointerNoToolTipActivity : AppCompatActivity() { 10 | 11 | override fun onCreate(savedInstanceState: Bundle?) { 12 | super.onCreate(savedInstanceState) 13 | setContentView(R.layout.activity_basic) 14 | val tourGuide = TourGuide.create(this) { 15 | overlay {} 16 | }.playOn(button1) 17 | 18 | button1.setOnClickListener { tourGuide.cleanUp() } 19 | button2.setOnClickListener { tourGuide.playOn(button1) } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/tourguide/tourguidedemo/OverlayCustomizationActivity.kt: -------------------------------------------------------------------------------- 1 | package tourguide.tourguidedemo 2 | 3 | import android.graphics.Color 4 | import android.os.Bundle 5 | import android.support.v7.app.AppCompatActivity 6 | import android.view.View 7 | import android.widget.Toast 8 | import kotlinx.android.synthetic.main.activity_overlay_customization.* 9 | import tourguide.tourguide.Overlay 10 | import tourguide.tourguide.TourGuide 11 | 12 | 13 | class OverlayCustomizationActivity : AppCompatActivity() { 14 | lateinit var tourGuide: TourGuide 15 | override fun onCreate(savedInstanceState: Bundle?) { 16 | super.onCreate(savedInstanceState) 17 | setContentView(R.layout.activity_overlay_customization) 18 | 19 | // the return handler is used to manipulate the cleanup of all the tutorial elements 20 | tourGuide = TourGuide.create(this) { 21 | pointer {} 22 | toolTip { 23 | title { "Hello!" } 24 | description { "Click to view tutorial. Next button is disabled until tutorial is viewed" } 25 | } 26 | overlay { 27 | disableClick { false } 28 | disableClickThroughHole { false } 29 | style { Overlay.Style.RECTANGLE } 30 | backgroundColor { Color.parseColor("#AAFF0000") } 31 | onClickListener { View.OnClickListener { tourGuide.cleanUp() } } 32 | } 33 | }.playOn(button) 34 | 35 | nextButton.setOnClickListener { Toast.makeText(this, "BOOM!", Toast.LENGTH_LONG).show() } 36 | button.setOnClickListener { tourGuide.cleanUp() } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/tourguide/tourguidedemo/RecyclerViewActivity.kt: -------------------------------------------------------------------------------- 1 | package tourguide.tourguidedemo 2 | 3 | import android.graphics.Color 4 | import android.os.Bundle 5 | import android.support.v7.app.AppCompatActivity 6 | import android.support.v7.widget.DividerItemDecoration 7 | import android.support.v7.widget.LinearLayoutManager 8 | import android.view.View 9 | import kotlinx.android.synthetic.main.activity_recycler_view.* 10 | import tourguide.tourguide.TourGuide 11 | import tourguide.tourguidedemo.recyclerview.RecyclerViewAdapter 12 | 13 | class RecyclerViewActivity : AppCompatActivity() { 14 | private val linearLayoutManager = LinearLayoutManager(this) 15 | 16 | private val tourGuide = TourGuide.create(this) { 17 | overlay { 18 | backgroundColor = Color.parseColor("#66FF0000") 19 | } 20 | } 21 | 22 | private val launchTourGuide = { view: View -> 23 | tourGuide.playOn(view) 24 | Unit 25 | } 26 | val dismissTourGuide = { 27 | tourGuide.cleanUp() 28 | Unit 29 | } 30 | 31 | override fun onCreate(savedInstanceState: Bundle?) { 32 | super.onCreate(savedInstanceState) 33 | setContentView(R.layout.activity_recycler_view) 34 | 35 | recyclerView.apply { 36 | adapter = RecyclerViewAdapter(launchTourGuide, dismissTourGuide) 37 | addItemDecoration(DividerItemDecoration(context, DividerItemDecoration.VERTICAL)) 38 | layoutManager = linearLayoutManager 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /app/src/main/java/tourguide/tourguidedemo/RoundedRectangleOverlayActivity.kt: -------------------------------------------------------------------------------- 1 | package tourguide.tourguidedemo 2 | 3 | import android.graphics.Color 4 | import android.os.Bundle 5 | import android.support.v7.app.AppCompatActivity 6 | import android.view.View 7 | import android.widget.Toast 8 | import kotlinx.android.synthetic.main.activity_overlay_customization.* 9 | import tourguide.tourguide.Overlay 10 | import tourguide.tourguide.TourGuide 11 | 12 | 13 | class RoundedRectangleOverlayActivity : AppCompatActivity() { 14 | lateinit var tourGuide: TourGuide 15 | override fun onCreate(savedInstanceState: Bundle?) { 16 | super.onCreate(savedInstanceState) 17 | setContentView(R.layout.activity_overlay_customization) 18 | tourGuide = TourGuide.create(this) { 19 | toolTip { 20 | title { "Hello!" } 21 | description { "Click to view tutorial. Next button is disabled until tutorial is viewed" } 22 | } 23 | overlay { 24 | disableClick { false } 25 | disableClickThroughHole { false } 26 | style { Overlay.Style.ROUNDED_RECTANGLE } 27 | roundedCornerRadius { 8 } 28 | onClickListener { View.OnClickListener { tourGuide.cleanUp() } } 29 | backgroundColor { Color.parseColor("#AAFF0000") } 30 | } 31 | pointer {} 32 | }.playOn(button) 33 | nextButton.setOnClickListener { Toast.makeText(this, "BOOM!", Toast.LENGTH_LONG).show() } 34 | 35 | button.setOnClickListener { tourGuide.cleanUp() } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/tourguide/tourguidedemo/ToolTipCustomizationActivity.kt: -------------------------------------------------------------------------------- 1 | package tourguide.tourguidedemo 2 | 3 | import android.graphics.Color 4 | import android.os.Bundle 5 | import android.support.v7.app.AppCompatActivity 6 | import android.view.Gravity 7 | import android.view.animation.BounceInterpolator 8 | import android.view.animation.TranslateAnimation 9 | import kotlinx.android.synthetic.main.activity_customization.* 10 | import tourguide.tourguide.TourGuide 11 | 12 | 13 | class ToolTipCustomizationActivity : AppCompatActivity() { 14 | 15 | override fun onCreate(savedInstanceState: Bundle?) { 16 | super.onCreate(savedInstanceState) 17 | setContentView(R.layout.activity_customization) 18 | 19 | val tourGuide = TourGuide.create(this) { 20 | toolTip { 21 | title { "Next Button" } 22 | description { "Click on Next button to proceed..." } 23 | textColor { Color.parseColor("#bdc3c7") } 24 | backgroundColor { Color.parseColor("#e74c3c") } 25 | shadow { true } 26 | gravity { Gravity.TOP or Gravity.LEFT } 27 | enterAnimation { 28 | TranslateAnimation(0f, 0f, 200f, 0f).apply { 29 | duration = 1000 30 | fillAfter = true 31 | interpolator = BounceInterpolator() 32 | } 33 | } 34 | } 35 | }.playOn(button) 36 | 37 | button.setOnClickListener { tourGuide.cleanUp() } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/tourguide/tourguidedemo/ToolTipGravityActivity.kt: -------------------------------------------------------------------------------- 1 | package tourguide.tourguidedemo 2 | 3 | import android.graphics.Color 4 | import android.os.Bundle 5 | import android.support.v7.app.AppCompatActivity 6 | import android.view.Gravity 7 | import kotlinx.android.synthetic.main.activity_tooltip_gravity_i.* 8 | import tourguide.tourguide.TourGuide 9 | 10 | 11 | class ToolTipGravityActivity : AppCompatActivity() { 12 | 13 | override fun onCreate(savedInstanceState: Bundle?) { 14 | /* Get parameters from main activity */ 15 | val tooltipNum = intent.getIntExtra(TOOLTIP_NUM, 1) 16 | 17 | super.onCreate(savedInstanceState) 18 | 19 | val gravity = when (tooltipNum) { 20 | 1 -> { 21 | setContentView(R.layout.activity_tooltip_gravity_i) 22 | Gravity.RIGHT or Gravity.BOTTOM 23 | } 24 | 2 -> { 25 | setContentView(R.layout.activity_tooltip_gravity_ii) 26 | Gravity.LEFT or Gravity.BOTTOM 27 | } 28 | 3 -> { 29 | setContentView(R.layout.activity_tooltip_gravity_iii) 30 | Gravity.LEFT or Gravity.TOP 31 | } 32 | else -> { 33 | setContentView(R.layout.activity_tooltip_gravity_iv) 34 | Gravity.RIGHT or Gravity.TOP 35 | } 36 | } 37 | 38 | val tourGuide = 39 | TourGuide.create(this) { 40 | toolTip { 41 | title { "Welcome!" } 42 | description { "Click on Get Started to begin..." } 43 | backgroundColor { Color.parseColor("#2980b9") } 44 | textColor { Color.parseColor("#FFFFFF") } 45 | gravity { gravity } 46 | shadow { true } 47 | } 48 | pointer {} 49 | overlay {} 50 | }.playOn(button) 51 | 52 | button.setOnClickListener { tourGuide.cleanUp() } 53 | 54 | } 55 | 56 | companion object { 57 | val TOOLTIP_NUM = "tooltip_num" 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/java/tourguide/tourguidedemo/ToolbarActivity.kt: -------------------------------------------------------------------------------- 1 | package tourguide.tourguidedemo 2 | 3 | import android.os.Bundle 4 | import android.support.v7.app.AppCompatActivity 5 | import android.view.Gravity 6 | import android.view.Menu 7 | import android.view.Window 8 | import android.view.WindowManager 9 | import android.widget.ImageView 10 | import kotlinx.android.synthetic.main.activity_toolbar.* 11 | import tourguide.tourguide.Overlay 12 | import tourguide.tourguide.Pointer 13 | import tourguide.tourguide.ToolTip 14 | import tourguide.tourguide.TourGuide 15 | 16 | 17 | class ToolbarActivity : AppCompatActivity() { 18 | 19 | private val hasStatusBar 20 | get() = intent.getBooleanExtra(STATUS_BAR, false) 21 | 22 | override fun onCreate(savedInstanceState: Bundle?) { 23 | /* Get parameters from main activity */ 24 | if (!hasStatusBar) { 25 | requestWindowFeature(Window.FEATURE_NO_TITLE) 26 | window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN) 27 | } 28 | 29 | super.onCreate(savedInstanceState) 30 | 31 | setContentView(R.layout.activity_toolbar) 32 | setSupportActionBar(toolbar) 33 | } 34 | 35 | override fun onCreateOptionsMenu(menu: Menu): Boolean { 36 | // Inflate the menu 37 | menuInflater.inflate(R.menu.menu_demo_main, menu) 38 | 39 | // We need to get the menu item as a View in order to work with TourGuide 40 | val menuItem = menu.getItem(0) 41 | val button = menuItem.actionView as ImageView 42 | 43 | // just adding some padding to look better 44 | val density = resources.displayMetrics.density 45 | val padding = (5 * density).toInt() 46 | button.setPadding(padding, padding, padding, padding) 47 | 48 | // set an image 49 | button.setImageDrawable(resources.getDrawable(android.R.drawable.ic_dialog_email)) 50 | 51 | val toolTip = ToolTip() 52 | .setTitle("Welcome!") 53 | .setDescription("Click on Get Started to begin...") 54 | .setGravity(Gravity.LEFT or Gravity.BOTTOM) 55 | 56 | val tourGuide = TourGuide.init(this).with(TourGuide.Technique.CLICK) 57 | .motionType(TourGuide.MotionType.CLICK_ONLY) 58 | .setPointer(Pointer()) 59 | .setToolTip(toolTip) 60 | .apply { 61 | overlay { Overlay() } 62 | }.playOn(button) 63 | button.setOnClickListener { tourGuide.cleanUp() } 64 | 65 | return true 66 | } 67 | 68 | companion object { 69 | val STATUS_BAR = "status_bar" 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /app/src/main/java/tourguide/tourguidedemo/main/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package tourguide.tourguidedemo.main 2 | 3 | import android.os.Bundle 4 | import android.support.v7.app.AppCompatActivity 5 | import kotlinx.android.synthetic.main.activity_tour_guide_demo_main.* 6 | 7 | import tourguide.tourguidedemo.R 8 | 9 | class MainActivity : AppCompatActivity() { 10 | override fun onCreate(savedInstanceState: Bundle?) { 11 | super.onCreate(savedInstanceState) 12 | setContentView(R.layout.activity_tour_guide_demo_main) 13 | mainRecyclerView.adapter = RecyclerViewAdapter() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/tourguide/tourguidedemo/main/MainAdapter.kt: -------------------------------------------------------------------------------- 1 | package tourguide.tourguidedemo.main 2 | 3 | import android.content.Intent 4 | import android.support.v4.content.ContextCompat 5 | import android.support.v7.app.AlertDialog 6 | import android.support.v7.widget.RecyclerView 7 | import android.view.LayoutInflater 8 | import android.view.View 9 | import android.view.ViewGroup 10 | import kotlinx.android.synthetic.main.row.view.* 11 | import tourguide.tourguidedemo.* 12 | 13 | class RecyclerViewAdapter : RecyclerView.Adapter() { 14 | private val numOfRow = 20 15 | private fun View.startActivity(intent: Intent) = ContextCompat.startActivity(context, intent, null) 16 | 17 | override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, position: Int) { 18 | viewHolder.itemView.apply { 19 | decorateBackground(this, position) 20 | 21 | when (position) { 22 | 0 -> { 23 | textView.text = "Basic Activity" 24 | setOnClickListener { 25 | startActivity(Intent(context, BasicActivity::class.java)) 26 | } 27 | } 28 | 1 -> { 29 | textView.text = "Pointer: color" 30 | setOnClickListener { 31 | startActivity(Intent(context, BasicActivity::class.java).apply { 32 | putExtra(BasicActivity.COLOR_DEMO, true) 33 | }) 34 | } 35 | } 36 | 2 -> { 37 | textView.text = "Pointer: gravity" 38 | setOnClickListener { 39 | startActivity(Intent(context, BasicActivity::class.java).apply { 40 | putExtra(BasicActivity.GRAVITY_DEMO, true) 41 | }) 42 | } 43 | } 44 | 3 -> { 45 | textView.text = "Toolbar Example" 46 | setOnClickListener { 47 | startActivity(Intent(context, ToolbarActivity::class.java).apply { 48 | putExtra(ToolbarActivity.STATUS_BAR, true) 49 | }) 50 | } 51 | } 52 | 4 -> { 53 | textView.text = "Toolbar Example\n(no status bar)" 54 | setOnClickListener { 55 | startActivity(Intent(context, ToolbarActivity::class.java).apply { 56 | putExtra(ToolbarActivity.STATUS_BAR, false) 57 | }) 58 | } 59 | } 60 | 5 -> { 61 | textView.text = "ToolTip Gravity I" 62 | setOnClickListener { 63 | startActivity(Intent(context, ToolTipGravityActivity::class.java).apply { 64 | putExtra(ToolTipGravityActivity.TOOLTIP_NUM, 1) 65 | }) 66 | } 67 | } 68 | 6 -> { 69 | textView.text = "ToolTip Gravity II" 70 | setOnClickListener { 71 | 72 | 73 | startActivity(Intent(context, ToolTipGravityActivity::class.java).apply { 74 | putExtra(ToolTipGravityActivity.TOOLTIP_NUM, 2) 75 | 76 | }) 77 | } 78 | } 79 | 7 -> { 80 | textView.text = "ToolTip Gravity III" 81 | setOnClickListener { 82 | startActivity(Intent(context, ToolTipGravityActivity::class.java).apply { 83 | putExtra(ToolTipGravityActivity.TOOLTIP_NUM, 3) 84 | }) 85 | } 86 | } 87 | 8 -> { 88 | textView.text = "ToolTip Gravity IV" 89 | setOnClickListener { 90 | 91 | startActivity(Intent(context, ToolTipGravityActivity::class.java).apply { 92 | putExtra(ToolTipGravityActivity.TOOLTIP_NUM, 4) 93 | }) 94 | } 95 | } 96 | 9 -> { 97 | textView.text = "ToolTip Customization" 98 | setOnClickListener { 99 | startActivity(Intent(context, ToolTipCustomizationActivity::class.java)) 100 | } 101 | } 102 | 10 -> { 103 | textView.text = "Multiple ToolTip" 104 | setOnClickListener { 105 | startActivity(Intent(context, MultipleToolTipActivity::class.java)) 106 | } 107 | } 108 | 11 -> { 109 | textView.text = "Overlay Customization" 110 | setOnClickListener { 111 | startActivity(Intent(context, OverlayCustomizationActivity::class.java)) 112 | } 113 | } 114 | 12 -> { 115 | textView.text = "ToolTip & Overlay only, no Pointer" 116 | setOnClickListener { 117 | startActivity(Intent(context, NoPointerActivity::class.java)) 118 | } 119 | } 120 | 13 -> { 121 | textView.text = "Overlay only, no Tooltip, no Pointer" 122 | setOnClickListener { 123 | startActivity(Intent(context, NoPointerNoToolTipActivity::class.java)) 124 | } 125 | } 126 | 14 -> { 127 | textView.text = "ToolTip & Pointer only, no Overlay" 128 | setOnClickListener { 129 | startActivity(Intent(context, NoOverlayActivity::class.java)) 130 | } 131 | } 132 | 15 -> { 133 | textView.text = "Button Tour (Manual)" 134 | infoIcon.visibility = View.VISIBLE 135 | infoIcon.setOnClickListener { 136 | val builder = AlertDialog.Builder(context) 137 | builder.setTitle("Button Tour").setMessage("- Button Tour example shows a sequence of TourGuide running on different buttons. \n- The method of proceeding to the next TourGuide is to press on the button itself. \n- This is suitable when you actually want the user to click on the button during the Tour.\n") 138 | builder.create().show() 139 | } 140 | setOnClickListener { 141 | startActivity(Intent(context, ManualSequenceActivity::class.java)) 142 | } 143 | } 144 | 16 -> { 145 | textView.text = "Navigational Drawer" 146 | setOnClickListener { 147 | startActivity(Intent(context, NavDrawerActivity::class.java)) 148 | } 149 | } 150 | 17 -> { 151 | textView.text = "Rounded Rectangle Overlay" 152 | setOnClickListener { 153 | startActivity(Intent(context, RoundedRectangleOverlayActivity::class.java)) 154 | } 155 | } 156 | 18 -> { 157 | textView.text = "Adjust Overlay Padding" 158 | setOnClickListener { 159 | startActivity(Intent(context, AdjustPaddingOverlayActivity::class.java)) 160 | } 161 | } 162 | else -> { 163 | textView.text = "Recycler View" 164 | setOnClickListener { 165 | startActivity(Intent(context, RecyclerViewActivity::class.java)) 166 | } 167 | } 168 | } 169 | } 170 | } 171 | 172 | private fun decorateBackground(view: View, position: Int) = 173 | view.apply { 174 | setBackgroundColor(ContextCompat.getColor(context, 175 | if (position % 2 == 0) { 176 | R.color.blue1 177 | } else { 178 | R.color.blue2 179 | })) 180 | } 181 | 182 | 183 | override fun getItemCount() = numOfRow 184 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = 185 | ViewHolder((LayoutInflater 186 | .from(parent.context) 187 | .inflate(R.layout.row, parent, false))) 188 | 189 | inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) 190 | } 191 | -------------------------------------------------------------------------------- /app/src/main/java/tourguide/tourguidedemo/recyclerview/RecyclerViewAdapter.kt: -------------------------------------------------------------------------------- 1 | package tourguide.tourguidedemo.recyclerview 2 | 3 | import android.support.v7.widget.RecyclerView 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import kotlinx.android.synthetic.main.row_recycler_view.view.* 8 | import tourguide.tourguidedemo.R 9 | 10 | class RecyclerViewAdapter(val launchTourGuide: (View) -> Unit, val dismissTourGuide: () -> Unit) : RecyclerView.Adapter() { 11 | 12 | override fun onBindViewHolder(_holder: RecyclerView.ViewHolder, position: Int) { 13 | val holder = _holder as DemoViewHolder 14 | holder.itemView.rowTextView 15 | .apply { text = "row #${position}" } 16 | .also { 17 | if (position == 1) { 18 | launchTourGuide.invoke(it) 19 | holder.itemView.setOnClickListener { 20 | dismissTourGuide.invoke() 21 | } 22 | } 23 | } 24 | } 25 | 26 | override fun getItemCount() = 10 27 | 28 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = 29 | LayoutInflater 30 | .from(parent.context) 31 | .inflate(R.layout.row_recycler_view, parent, false) 32 | .let { DemoViewHolder(it) } 33 | 34 | class DemoViewHolder(item: View) : RecyclerView.ViewHolder(item) 35 | 36 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/tour_guide_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/worker8/TourGuide/949c4a484cb98febcc223d19d960dbc2f5c5a4c4/app/src/main/res/drawable-hdpi/tour_guide_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/tour_guide_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/worker8/TourGuide/949c4a484cb98febcc223d19d960dbc2f5c5a4c4/app/src/main/res/drawable-mdpi/tour_guide_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/tour_guide_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/worker8/TourGuide/949c4a484cb98febcc223d19d960dbc2f5c5a4c4/app/src/main/res/drawable-xhdpi/tour_guide_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/tour_guide_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/worker8/TourGuide/949c4a484cb98febcc223d19d960dbc2f5c5a4c4/app/src/main/res/drawable-xxhdpi/tour_guide_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/toolbar_drop_shadow.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_basic.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 13 | 14 |