├── .gitignore ├── AndroidManifest.xml ├── README.md ├── ant.properties ├── assets └── fonts │ ├── roboto_light.ttf │ └── roboto_regular.ttf ├── build.xml ├── gen └── com │ └── eluleci │ └── appintroduction │ ├── BuildConfig.java │ ├── Manifest.java │ └── R.java ├── local.properties ├── proguard-project.txt ├── project.properties ├── res ├── drawable-hdpi │ └── ic_launcher.png ├── drawable-ldpi │ └── ic_launcher.png ├── drawable-mdpi │ └── ic_launcher.png ├── drawable-xhdpi │ └── ic_launcher.png ├── drawable │ ├── arrow_alizarin.png │ ├── arrow_amethyst.png │ ├── arrow_asbestos.png │ ├── arrow_belize_hole.png │ ├── arrow_carrot.png │ ├── arrow_clouds.png │ ├── arrow_concrete.png │ ├── arrow_emerald.png │ ├── arrow_green_sea.png │ ├── arrow_midnight_blue.png │ ├── arrow_neprhitis.png │ ├── arrow_orange.png │ ├── arrow_peter_river.png │ ├── arrow_pomegranate.png │ ├── arrow_pumpkin.png │ ├── arrow_silver.png │ ├── arrow_sunflower.png │ ├── arrow_turquoise.png │ ├── arrow_wet_asphalt.png │ └── arrow_wisteria.png ├── layout │ └── main.xml └── values │ ├── colors.xml │ └── strings.xml ├── screenshots ├── 1.png ├── 10.png ├── 2.png ├── 3.png ├── 4.png ├── 5.png ├── 6.png ├── 7.png ├── 8.png ├── 9.png └── flatuicolors.png └── src └── com └── eluleci └── appintroduction ├── AppIntroduction.java ├── Step.java ├── TextBaloon.java ├── listeners ├── StepActionListener.java └── UserActionListener.java └── views ├── DynamicDrawable.java ├── TextViewLight.java └── TextViewRegular.java /.gitignore: -------------------------------------------------------------------------------- 1 | # built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # files for the dex VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # generated files 12 | bin/ 13 | gen/ 14 | 15 | # Local configuration file (sdk path, etc) 16 | local.properties 17 | 18 | # Eclipse project files 19 | .classpath 20 | .project 21 | 22 | # Proguard folder generated by Eclipse 23 | proguard/ 24 | 25 | # Intellij project files 26 | *.iml 27 | *.ipr 28 | *.iws 29 | .idea/ -------------------------------------------------------------------------------- /AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | App Introduction 2 | =================== 3 | 4 | App Introduction is a library that helps to create introduction menu for users. 5 | 6 | Only thing that you need to do is giving the id of the element to show (if you want to point an element) and 7 | write the message. You can choose pointing type like vertical or horizontal. Then the rest is done by library. 8 | 9 | The messages that you add to same AppIntroduction object are stored and showed to the user one by one. 10 | When user sees messages of an Activity once, they will not be shown again. You can select one of the 20 themes. 11 | You can create listeners for doing some actions before and after each step, so you can have full control on steps. 12 | Also you can create a listener to know when user dismisses the AppIntroduction. 13 | 14 | Features included 15 | ----------------- 16 | * Showing the message in the middle. 17 | * Showing the message with horizontal pointer. 18 | * Showing the message with vertical pointer. 19 | * Remembering past (not showing messages if already shown). 20 | * Changing theme (Selecting one of the colors in http://flatuicolors.com). 21 | * Creating listeners for before/after events for each step. 22 | * Creating listeners for user dismiss. 23 | 24 | Screenshots 25 | ----------- 26 | 27 | ![Message in the middle][1].![Message with vertical pointer][2].![Message with horizontal pointer][3].![Message with vertical pointer again.][4] 28 | 29 | 30 | Theme Screenshots 31 | ----------- 32 | 33 | ![Orange][5].![Wet Asphalt][6].![Turquoise][7].![Asbestos][8].![Wisteria][9].![Pomegranate][10] 34 | 35 | 36 | Colors 37 | ----------- 38 | 39 | ![colors][11] 40 | 41 | [1]: https://raw.github.com/eluleci/appintroduction/master/screenshots/1.png 42 | [2]: https://raw.github.com/eluleci/appintroduction/master/screenshots/2.png 43 | [3]: https://raw.github.com/eluleci/appintroduction/master/screenshots/3.png 44 | [4]: https://raw.github.com/eluleci/appintroduction/master/screenshots/4.png 45 | [5]: https://raw.github.com/eluleci/appintroduction/master/screenshots/5.png 46 | [6]: https://raw.github.com/eluleci/appintroduction/master/screenshots/6.png 47 | [7]: https://raw.github.com/eluleci/appintroduction/master/screenshots/7.png 48 | [8]: https://raw.github.com/eluleci/appintroduction/master/screenshots/8.png 49 | [9]: https://raw.github.com/eluleci/appintroduction/master/screenshots/9.png 50 | [10]: https://raw.github.com/eluleci/appintroduction/master/screenshots/10.png 51 | [11]: https://raw.github.com/eluleci/appintroduction/master/screenshots/flatuicolors.png 52 | 53 | ## Usage 54 | 55 | For using this library in Android Studio (IntelliJ IDEA) you need to activate including assets from dependencies. 56 | - Open project structure (Right Click on Project -> 'Open Module Settings') 57 | - Select 'Facets' from left menu 58 | - Select 'Compiler' tab at right 59 | - Activate 'Include assets from dependencies into APK' beneath 'Resources Packaging' 60 | 61 | ```java 62 | 63 | AppIntroduction appIntroduction = new AppIntroduction(this); 64 | 65 | // remembering past. not showing again if already shown before 66 | appIntroduction.rememberPast(true); 67 | 68 | // changing theme. selecting one of the colors 69 | appIntroduction.setTheme(AppIntroduction.TURQUOISE); 70 | 71 | 72 | 73 | // adding message into middle 74 | appIntroduction.addStep(new Step(getResources().getString(R.string.uc_main_1))); 75 | 76 | // adding message with vertical pointer 77 | appIntroduction.addStep(new Step(R.id.search, 78 | getResources().getString(R.string.uc_main_3), AppIntroduction.SIDE_VERTICAL)); 79 | 80 | // adding message with horizontal pointer 81 | appIntroduction.addStep(new Step(R.id.next, 82 | getResources().getString(R.string.uc_shuffle_3), AppIntroduction.SIDE_HORIZONTAL)); 83 | 84 | 85 | 86 | // constructing AppIntroduction for listening dismiss of the user 87 | appIntroduction = new AppIntroduction(this) { 88 | @Override 89 | public void onDismiss() { 90 | super.onDismiss(); 91 | // handle user's dismiss 92 | } 93 | }; 94 | 95 | 96 | 97 | // listeners for steps. you can do some changes before or after a step 98 | appIntroduction.addStep(new Step(R.id.second_language, 99 | getResources().getString(R.string.uc_shuffle_11), AppIntroduction.SIDE_VERTICAL, new StepActionListener() { 100 | @Override 101 | public void beforeMessageShown() { 102 | // do something before showing message 103 | } 104 | 105 | @Override 106 | public void afterMessageShown() { 107 | // do something after showing message 108 | } 109 | })); 110 | 111 | // starting introduction. you CANNOT call this in onCreate method of activity. 112 | // because the content view of activity won't be ready in onCreate 113 | appIntroduction.start(); 114 | 115 | // starting introduction. you can call this in onCreate method in activity. 116 | // it will wait for 0.5 seconds for content view to be ready. 117 | appIntroduction.startWithDelay(); 118 | 119 | ``` 120 | 121 | -------------------------------------------------------------------------------- /ant.properties: -------------------------------------------------------------------------------- 1 | # This file is used to override default values used by the Ant build system. 2 | # 3 | # This file must be checked into Version Control Systems, as it is 4 | # integral to the build system of your project. 5 | 6 | # This file is only used by the Ant script. 7 | 8 | # You can use this to override default values such as 9 | # 'source.dir' for the location of your java source folder and 10 | # 'out.dir' for the location of your output folder. 11 | 12 | # You can also use it define how the release builds are signed by declaring 13 | # the following properties: 14 | # 'key.store' for the location of your keystore and 15 | # 'key.alias' for the name of the key to use. 16 | # The password will be asked during the build when you use the 'release' target. 17 | 18 | -------------------------------------------------------------------------------- /assets/fonts/roboto_light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/assets/fonts/roboto_light.ttf -------------------------------------------------------------------------------- /assets/fonts/roboto_regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/assets/fonts/roboto_regular.ttf -------------------------------------------------------------------------------- /build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 29 | 30 | 31 | 35 | 36 | 37 | 38 | 39 | 40 | 49 | 50 | 51 | 52 | 56 | 57 | 69 | 70 | 71 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /gen/com/eluleci/appintroduction/BuildConfig.java: -------------------------------------------------------------------------------- 1 | /*___Generated_by_IDEA___*/ 2 | 3 | /** Automatically generated file. DO NOT MODIFY */ 4 | package com.eluleci.appintroduction; 5 | 6 | public final class BuildConfig { 7 | public final static boolean DEBUG = true; 8 | } -------------------------------------------------------------------------------- /gen/com/eluleci/appintroduction/Manifest.java: -------------------------------------------------------------------------------- 1 | /*___Generated_by_IDEA___*/ 2 | 3 | package com.eluleci.appintroduction; 4 | 5 | /* This stub is for using by IDE only. It is NOT the Manifest class actually packed into APK */ 6 | public final class Manifest { 7 | } -------------------------------------------------------------------------------- /gen/com/eluleci/appintroduction/R.java: -------------------------------------------------------------------------------- 1 | /*___Generated_by_IDEA___*/ 2 | 3 | package com.eluleci.appintroduction; 4 | 5 | /* This stub is for using by IDE only. It is NOT the R class actually packed into APK */ 6 | public final class R { 7 | } -------------------------------------------------------------------------------- /local.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must *NOT* be checked into Version Control Systems, 5 | # as it contains information specific to your local configuration. 6 | 7 | # location of the SDK. This is only used by Ant 8 | # For customization when using a Version Control System, please read the 9 | # header note. 10 | sdk.dir=C:\\Program Files\\Android\\android-sdk 11 | -------------------------------------------------------------------------------- /proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | android.library=true 14 | # Project target. 15 | target=Google Inc.:Google APIs:16 16 | -------------------------------------------------------------------------------- /res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-ldpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/res/drawable-ldpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable/arrow_alizarin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/res/drawable/arrow_alizarin.png -------------------------------------------------------------------------------- /res/drawable/arrow_amethyst.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/res/drawable/arrow_amethyst.png -------------------------------------------------------------------------------- /res/drawable/arrow_asbestos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/res/drawable/arrow_asbestos.png -------------------------------------------------------------------------------- /res/drawable/arrow_belize_hole.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/res/drawable/arrow_belize_hole.png -------------------------------------------------------------------------------- /res/drawable/arrow_carrot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/res/drawable/arrow_carrot.png -------------------------------------------------------------------------------- /res/drawable/arrow_clouds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/res/drawable/arrow_clouds.png -------------------------------------------------------------------------------- /res/drawable/arrow_concrete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/res/drawable/arrow_concrete.png -------------------------------------------------------------------------------- /res/drawable/arrow_emerald.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/res/drawable/arrow_emerald.png -------------------------------------------------------------------------------- /res/drawable/arrow_green_sea.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/res/drawable/arrow_green_sea.png -------------------------------------------------------------------------------- /res/drawable/arrow_midnight_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/res/drawable/arrow_midnight_blue.png -------------------------------------------------------------------------------- /res/drawable/arrow_neprhitis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/res/drawable/arrow_neprhitis.png -------------------------------------------------------------------------------- /res/drawable/arrow_orange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/res/drawable/arrow_orange.png -------------------------------------------------------------------------------- /res/drawable/arrow_peter_river.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/res/drawable/arrow_peter_river.png -------------------------------------------------------------------------------- /res/drawable/arrow_pomegranate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/res/drawable/arrow_pomegranate.png -------------------------------------------------------------------------------- /res/drawable/arrow_pumpkin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/res/drawable/arrow_pumpkin.png -------------------------------------------------------------------------------- /res/drawable/arrow_silver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/res/drawable/arrow_silver.png -------------------------------------------------------------------------------- /res/drawable/arrow_sunflower.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/res/drawable/arrow_sunflower.png -------------------------------------------------------------------------------- /res/drawable/arrow_turquoise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/res/drawable/arrow_turquoise.png -------------------------------------------------------------------------------- /res/drawable/arrow_wet_asphalt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/res/drawable/arrow_wet_asphalt.png -------------------------------------------------------------------------------- /res/drawable/arrow_wisteria.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/res/drawable/arrow_wisteria.png -------------------------------------------------------------------------------- /res/layout/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #1abc9c 5 | #2ecc71 6 | #3498db 7 | #9b59b6 8 | #34495e 9 | #16a085 10 | #27ae60 11 | #2980b9 12 | #8e44ad 13 | #2c3e50 14 | #f1c40f 15 | #e67e22 16 | #e74c3c 17 | #ecf0f1 18 | #95a5a6 19 | #f39c12 20 | #d35400 21 | #c0392b 22 | #bdc3c7 23 | #7f8c8d 24 | 25 | 26 | -------------------------------------------------------------------------------- /res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | ACTIVITY_ENTRY_NAME 4 | 5 | -------------------------------------------------------------------------------- /screenshots/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/screenshots/1.png -------------------------------------------------------------------------------- /screenshots/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/screenshots/10.png -------------------------------------------------------------------------------- /screenshots/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/screenshots/2.png -------------------------------------------------------------------------------- /screenshots/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/screenshots/3.png -------------------------------------------------------------------------------- /screenshots/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/screenshots/4.png -------------------------------------------------------------------------------- /screenshots/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/screenshots/5.png -------------------------------------------------------------------------------- /screenshots/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/screenshots/6.png -------------------------------------------------------------------------------- /screenshots/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/screenshots/7.png -------------------------------------------------------------------------------- /screenshots/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/screenshots/8.png -------------------------------------------------------------------------------- /screenshots/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/screenshots/9.png -------------------------------------------------------------------------------- /screenshots/flatuicolors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eluleci/appintroduction/17178a4d56e9138bf48f6e04fc0663f2e7acdd6c/screenshots/flatuicolors.png -------------------------------------------------------------------------------- /src/com/eluleci/appintroduction/AppIntroduction.java: -------------------------------------------------------------------------------- 1 | package com.eluleci.appintroduction; 2 | 3 | import android.app.Activity; 4 | import android.content.SharedPreferences; 5 | import com.eluleci.appintroduction.listeners.UserActionListener; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | /** 11 | * Created with IntelliJ IDEA. 12 | * User: eluleci 13 | * Date: 08.08.2013 14 | * Time: 22:21 15 | */ 16 | public class AppIntroduction implements UserActionListener { 17 | 18 | public static final int TURQUOISE = 1; 19 | public static final int EMERALD = 2; 20 | public static final int PETER_RIVER = 3; 21 | public static final int AMETHYST = 4; 22 | public static final int WET_ASPHALT = 5; 23 | public static final int GREEN_SEA = 6; 24 | public static final int NEPHRITIS = 7; 25 | public static final int BELIZE_HOLE = 8; 26 | public static final int WISTERIA = 9; 27 | public static final int MIDNIGHT_BLUE = 10; 28 | public static final int SUN_FLOWER = 11; 29 | public static final int CARROT = 12; 30 | public static final int ALIZARIN = 13; 31 | public static final int CLOUDS = 14; 32 | public static final int CONCRETE = 15; 33 | public static final int ORANGE = 16; 34 | public static final int PUMPKIN = 17; 35 | public static final int POMEGRANATE = 18; 36 | public static final int SILVER = 19; 37 | public static final int ASBESTOS = 20; 38 | 39 | public static final int SIDE_HORIZONTAL = 0; 40 | public static final int SIDE_VERTICAL = 1; 41 | public static final int SIDE_NONE = -1; 42 | public static final int NO_VIEW = -5; 43 | private static final String PREF_NAME = "AppIntroductionPreferences"; 44 | private boolean checkUsersChoice = false; 45 | private Activity mContext; 46 | private TextBaloon textBaloon; 47 | private List steps = new ArrayList(); 48 | private int currentElement = -1; 49 | private boolean isOver = false; 50 | private boolean isActive = false; 51 | 52 | public AppIntroduction(Activity activity) { 53 | mContext = activity; 54 | textBaloon = new TextBaloon(activity, this); 55 | } 56 | 57 | public void addStep(Step step) { 58 | steps.add(step); 59 | } 60 | 61 | public void start() { 62 | 63 | // don't start if shown before 64 | if (isShownBefore() && checkUsersChoice) return; 65 | 66 | SharedPreferences settings = mContext.getSharedPreferences(PREF_NAME, 0); 67 | SharedPreferences.Editor editor = settings.edit(); 68 | editor.putBoolean(mContext.getLocalClassName(), true); 69 | editor.commit(); 70 | 71 | onNextClicked(); 72 | isActive = true; 73 | } 74 | 75 | public void startWithDelay() { 76 | Thread changeTextThread = new Thread() { 77 | @Override 78 | public void run() { 79 | try { 80 | Thread.sleep(500); 81 | } catch (InterruptedException e) { 82 | } 83 | 84 | mContext.runOnUiThread(new Runnable() { 85 | @Override 86 | public void run() { 87 | AppIntroduction.this.start(); 88 | } 89 | }); 90 | } 91 | }; 92 | changeTextThread.start(); 93 | } 94 | 95 | public void rememberPast(boolean remember) { 96 | checkUsersChoice = remember; 97 | } 98 | 99 | public void setTheme(int theme){ 100 | textBaloon.setTheme(theme); 101 | } 102 | 103 | public boolean isShownBefore() { 104 | SharedPreferences settings = mContext.getSharedPreferences(PREF_NAME, 0); 105 | 106 | boolean isShownBefore = settings.getBoolean(mContext.getLocalClassName(), false); 107 | return isShownBefore; 108 | } 109 | 110 | public void next() { 111 | if (isActive()) 112 | onNextClicked(); 113 | } 114 | 115 | @Override 116 | public void onNextClicked() { 117 | 118 | if (isOver) return; 119 | 120 | if (currentElement != -1) 121 | steps.get(currentElement).getStepActionListener().afterMessageShown(); 122 | 123 | if (++currentElement == steps.size()) { 124 | textBaloon.hide(); 125 | isOver = true; 126 | return; 127 | } 128 | 129 | steps.get(currentElement).getStepActionListener().beforeMessageShown(); 130 | textBaloon.changeElement(steps.get(currentElement)); 131 | } 132 | 133 | @Override 134 | public void onDismiss() { 135 | textBaloon.hide(); 136 | } 137 | 138 | public boolean isActive() { 139 | return isActive; 140 | } 141 | 142 | public TextBaloon getTextBaloon() { 143 | return textBaloon; 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/com/eluleci/appintroduction/Step.java: -------------------------------------------------------------------------------- 1 | package com.eluleci.appintroduction; 2 | 3 | import com.eluleci.appintroduction.listeners.StepActionListener; 4 | 5 | /** 6 | * Created with IntelliJ IDEA. 7 | * User: eluleci 8 | * Date: 19.09.2013 9 | * Time: 23:21 10 | */ 11 | public class Step { 12 | 13 | private int viewId; 14 | private String message; 15 | private int side; 16 | 17 | private StepActionListener stepActionListener = new StepActionListener() { 18 | @Override 19 | public void beforeMessageShown() { 20 | } 21 | 22 | @Override 23 | public void afterMessageShown() { 24 | } 25 | }; 26 | 27 | public Step(String message) { 28 | this.viewId = AppIntroduction.NO_VIEW; 29 | this.message = message; 30 | this.side = AppIntroduction.SIDE_NONE; 31 | } 32 | 33 | public Step(String message, StepActionListener stepActionListener) { 34 | this.viewId = AppIntroduction.NO_VIEW; 35 | this.message = message; 36 | this.side = AppIntroduction.SIDE_NONE; 37 | this.stepActionListener = stepActionListener; 38 | } 39 | 40 | public Step(int viewId, String message, int side) { 41 | this.viewId = viewId; 42 | this.message = message; 43 | this.side = side; 44 | } 45 | 46 | public Step(int viewId, String message, int side, StepActionListener stepActionListener) { 47 | this.viewId = viewId; 48 | this.message = message; 49 | this.side = side; 50 | this.stepActionListener = stepActionListener; 51 | } 52 | 53 | public int getViewId() { 54 | return viewId; 55 | } 56 | 57 | public String getMessage() { 58 | return message; 59 | } 60 | 61 | public int getSide() { 62 | return side; 63 | } 64 | 65 | public void setStepActionListener(StepActionListener stepActionListener) { 66 | this.stepActionListener = stepActionListener; 67 | } 68 | 69 | public StepActionListener getStepActionListener() { 70 | return stepActionListener; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/com/eluleci/appintroduction/TextBaloon.java: -------------------------------------------------------------------------------- 1 | package com.eluleci.appintroduction; 2 | 3 | import android.app.Activity; 4 | import android.graphics.Color; 5 | import android.graphics.drawable.Drawable; 6 | import android.util.Log; 7 | import android.view.Display; 8 | import android.view.Gravity; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.view.animation.AlphaAnimation; 12 | import android.view.animation.RotateAnimation; 13 | import android.widget.*; 14 | import com.eluleci.appintroduction.listeners.UserActionListener; 15 | import com.eluleci.appintroduction.views.DynamicDrawable; 16 | import com.eluleci.appintroduction.views.TextViewLight; 17 | import com.eluleci.appintroduction.views.TextViewRegular; 18 | 19 | /** 20 | * Created with IntelliJ IDEA. 21 | * User: eluleci 22 | * Date: 08.08.2013 23 | * Time: 22:19 24 | */ 25 | public class TextBaloon extends RelativeLayout { 26 | 27 | private final int indicatorSize = 50; 28 | private final int containerMargin = 10; 29 | private final int textPadding = 10; 30 | private Activity mContext; 31 | private UserActionListener userActionListener; 32 | private View backgroundLayer; 33 | private TextView explanationTextView; 34 | private LinearLayout container; 35 | private RelativeLayout footerContainer; 36 | private ImageView indicator; 37 | private TextView exit; 38 | private TextView next; 39 | private AlphaAnimation showAnim; 40 | private AlphaAnimation hideAnim; 41 | private int animDuration = 100; 42 | private int screenWidth; 43 | private int screenHeight; 44 | private int textSize = 20; 45 | private View element; 46 | 47 | public TextBaloon(Activity activity, UserActionListener ual) { 48 | super(activity); 49 | mContext = activity; 50 | userActionListener = ual; 51 | 52 | setVisibility(GONE); 53 | 54 | Display display = activity.getWindowManager().getDefaultDisplay(); 55 | screenWidth = display.getWidth(); 56 | screenHeight = display.getHeight(); 57 | 58 | ViewGroup root = (ViewGroup) activity.getWindow().getDecorView().findViewById(android.R.id.content); 59 | 60 | // adding a layer to the background to avoid the clicks to other views 61 | backgroundLayer = new View(mContext); 62 | backgroundLayer.setVisibility(GONE); 63 | root.addView(backgroundLayer); 64 | backgroundLayer.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 65 | ViewGroup.LayoutParams.MATCH_PARENT)); 66 | //backgroundLayer.setBackgroundColor(Color.parseColor("#11000000")); 67 | backgroundLayer.setOnClickListener(new OnClickListener() { 68 | @Override 69 | public void onClick(View v) { 70 | } 71 | }); 72 | 73 | 74 | this.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 75 | ViewGroup.LayoutParams.MATCH_PARENT)); 76 | 77 | root.addView(this); 78 | 79 | indicator = new ImageView(activity); 80 | this.addView(indicator); 81 | indicator.setLayoutParams(new LayoutParams(indicatorSize, indicatorSize)); 82 | 83 | container = new LinearLayout(activity); 84 | container.setOrientation(LinearLayout.VERTICAL); 85 | this.addView(container); 86 | container.setLayoutParams(new LayoutParams(screenWidth, ViewGroup.LayoutParams.WRAP_CONTENT)); 87 | 88 | setTheme(AppIntroduction.PETER_RIVER); 89 | 90 | explanationTextView = new TextViewLight(activity); 91 | explanationTextView.setTextColor(Color.WHITE); 92 | explanationTextView.setGravity(Gravity.CENTER); 93 | explanationTextView.setPadding(textPadding, textPadding * 2, textPadding, textPadding * 2); 94 | explanationTextView.setTextSize(textSize); 95 | container.addView(explanationTextView); 96 | explanationTextView.setLayoutParams(new LinearLayout.LayoutParams( 97 | ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); 98 | 99 | footerContainer = new RelativeLayout(activity); 100 | footerContainer.setAlpha(0.6f); 101 | container.addView(footerContainer); 102 | footerContainer.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 103 | ViewGroup.LayoutParams.WRAP_CONTENT)); 104 | 105 | LayoutParams nextButtonParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 106 | ViewGroup.LayoutParams.WRAP_CONTENT); 107 | nextButtonParams.addRule(ALIGN_PARENT_RIGHT, -1); 108 | 109 | next = new TextViewRegular(activity); 110 | next.setTextColor(Color.WHITE); 111 | next.setText("NEXT"); 112 | next.setTextSize(textSize); 113 | next.setPadding(textPadding, textPadding, textPadding * 2, textPadding); 114 | footerContainer.addView(next); 115 | next.setLayoutParams(nextButtonParams); 116 | 117 | exit = new TextViewRegular(activity); 118 | exit.setTextColor(Color.WHITE); 119 | exit.setText("CANCEL"); 120 | exit.setTextSize(textSize); 121 | exit.setPadding(textPadding * 2, textPadding, textPadding, textPadding); 122 | footerContainer.addView(exit); 123 | exit.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 124 | ViewGroup.LayoutParams.WRAP_CONTENT)); 125 | 126 | hideAnim = new AlphaAnimation(1f, 0f); 127 | hideAnim.setDuration(animDuration); 128 | hideAnim.setFillAfter(true); 129 | 130 | showAnim = new AlphaAnimation(0f, 1f); 131 | showAnim.setDuration(animDuration); 132 | showAnim.setFillAfter(true); 133 | showAnim.setStartOffset(animDuration); 134 | 135 | 136 | next.setOnClickListener(new OnClickListener() { 137 | @Override 138 | public void onClick(View v) { 139 | userActionListener.onNextClicked(); 140 | } 141 | }); 142 | 143 | exit.setOnClickListener(new OnClickListener() { 144 | @Override 145 | public void onClick(View v) { 146 | userActionListener.onDismiss(); 147 | } 148 | }); 149 | } 150 | 151 | protected void setTheme(int theme){ 152 | 153 | int indicatorDrawableId = R.drawable.arrow_peter_river; 154 | int containerBackDrawableId = R.color.peter_river; 155 | 156 | switch (theme){ 157 | case AppIntroduction.TURQUOISE: 158 | indicatorDrawableId = R.drawable.arrow_turquoise; 159 | containerBackDrawableId = R.color.turquoise; 160 | break; 161 | case AppIntroduction.EMERALD: 162 | indicatorDrawableId = R.drawable.arrow_emerald; 163 | containerBackDrawableId = R.color.emerald; 164 | break; 165 | case AppIntroduction.PETER_RIVER: 166 | indicatorDrawableId = R.drawable.arrow_peter_river; 167 | containerBackDrawableId = R.color.peter_river; 168 | break; 169 | case AppIntroduction.AMETHYST: 170 | indicatorDrawableId = R.drawable.arrow_amethyst; 171 | containerBackDrawableId = R.color.amethyst; 172 | break; 173 | case AppIntroduction.WET_ASPHALT: 174 | indicatorDrawableId = R.drawable.arrow_wet_asphalt; 175 | containerBackDrawableId = R.color.wet_asphalt; 176 | break; 177 | case AppIntroduction.GREEN_SEA: 178 | indicatorDrawableId = R.drawable.arrow_green_sea; 179 | containerBackDrawableId = R.color.green_sea; 180 | break; 181 | case AppIntroduction.NEPHRITIS: 182 | indicatorDrawableId = R.drawable.arrow_neprhitis; 183 | containerBackDrawableId = R.color.nephritis; 184 | break; 185 | case AppIntroduction.BELIZE_HOLE: 186 | indicatorDrawableId = R.drawable.arrow_belize_hole; 187 | containerBackDrawableId = R.color.belize_hole; 188 | break; 189 | case AppIntroduction.WISTERIA: 190 | indicatorDrawableId = R.drawable.arrow_wisteria; 191 | containerBackDrawableId = R.color.wisteria; 192 | break; 193 | case AppIntroduction.MIDNIGHT_BLUE: 194 | indicatorDrawableId = R.drawable.arrow_midnight_blue; 195 | containerBackDrawableId = R.color.midnight_blue; 196 | break; 197 | case AppIntroduction.SUN_FLOWER: 198 | indicatorDrawableId = R.drawable.arrow_sunflower; 199 | containerBackDrawableId = R.color.sun_flower; 200 | break; 201 | case AppIntroduction.CARROT: 202 | indicatorDrawableId = R.drawable.arrow_carrot; 203 | containerBackDrawableId = R.color.carrot; 204 | break; 205 | case AppIntroduction.ALIZARIN: 206 | indicatorDrawableId = R.drawable.arrow_alizarin; 207 | containerBackDrawableId = R.color.alizarin; 208 | break; 209 | case AppIntroduction.CLOUDS: 210 | indicatorDrawableId = R.drawable.arrow_clouds; 211 | containerBackDrawableId = R.color.clouds; 212 | break; 213 | case AppIntroduction.CONCRETE: 214 | indicatorDrawableId = R.drawable.arrow_concrete; 215 | containerBackDrawableId = R.color.concrete; 216 | break; 217 | case AppIntroduction.ORANGE: 218 | indicatorDrawableId = R.drawable.arrow_orange; 219 | containerBackDrawableId = R.color.orange; 220 | break; 221 | case AppIntroduction.PUMPKIN: 222 | indicatorDrawableId = R.drawable.arrow_pumpkin; 223 | containerBackDrawableId = R.color.pumpkin; 224 | break; 225 | case AppIntroduction.POMEGRANATE: 226 | indicatorDrawableId = R.drawable.arrow_pomegranate; 227 | containerBackDrawableId = R.color.pomegranate; 228 | break; 229 | case AppIntroduction.SILVER: 230 | indicatorDrawableId = R.drawable.arrow_silver; 231 | containerBackDrawableId = R.color.silver; 232 | break; 233 | case AppIntroduction.ASBESTOS: 234 | indicatorDrawableId = R.drawable.arrow_asbestos; 235 | containerBackDrawableId = R.color.asbestos; 236 | break; 237 | } 238 | 239 | 240 | Drawable indicatorDrawable = mContext.getResources().getDrawable(indicatorDrawableId); 241 | DynamicDrawable containerBackDrawable= new DynamicDrawable( 242 | mContext.getResources().getColor(containerBackDrawableId), 4); 243 | 244 | indicator.setImageDrawable(indicatorDrawable); 245 | if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN) { 246 | container.setBackgroundDrawable(containerBackDrawable); 247 | } else { 248 | container.setBackground(containerBackDrawable); 249 | } 250 | } 251 | 252 | protected void changeElement(final Step step) { 253 | 254 | if (step.getViewId() != AppIntroduction.NO_VIEW) 255 | element = mContext.findViewById(step.getViewId()); 256 | else 257 | element = null; 258 | 259 | hide(); 260 | 261 | // This thread is used to wait for the hide animation. 262 | Thread changeTextThread = new Thread() { 263 | @Override 264 | public void run() { 265 | try { 266 | Thread.sleep(animDuration); 267 | } catch (InterruptedException e) { 268 | } 269 | 270 | mContext.runOnUiThread(new Runnable() { 271 | @Override 272 | public void run() { 273 | explanationTextView.setText(step.getMessage()); 274 | } 275 | }); 276 | } 277 | }; 278 | changeTextThread.start(); 279 | 280 | // This thread is used for waiting the size change of the container. 281 | // The size is not changed directly after changing the text. 282 | // So we need to wait a while. 283 | Thread setSizeThread = new 284 | 285 | Thread() { 286 | @Override 287 | public void run() { 288 | try { 289 | Thread.sleep(animDuration + 50); 290 | } catch (InterruptedException e) { 291 | } 292 | 293 | mContext.runOnUiThread(new Runnable() { 294 | @Override 295 | public void run() { 296 | 297 | setVisibility(VISIBLE); 298 | 299 | if (step.getSide() == AppIntroduction.SIDE_NONE) { 300 | // if side is none, the message is shown in the middle of the screen 301 | showMessageInCenter(); 302 | return; 303 | } 304 | 305 | int elementWidth = element.getWidth(); 306 | int elementHeight = element.getHeight(); 307 | int elementTop = getRelativeTop(element) - elementHeight / 2; 308 | int elementLeft = getRelativeLeft(element); 309 | 310 | int indicatorLeft; 311 | int indicatorTop; 312 | 313 | container.setLayoutParams(new LayoutParams(screenWidth, 314 | ViewGroup.LayoutParams.WRAP_CONTENT)); 315 | 316 | if (step.getSide() == AppIntroduction.SIDE_VERTICAL) { 317 | int indicatorHorizontalCenter = elementLeft + elementWidth / 2; 318 | 319 | indicatorLeft = indicatorHorizontalCenter - indicatorSize / 2; 320 | indicatorTop = elementHeight + elementTop; 321 | if (elementTop + elementHeight > screenHeight / 2) { 322 | // indicator looking down 323 | indicatorTop -= (elementHeight + indicatorSize); 324 | rotate(0); 325 | 326 | LayoutParams layoutParams = (LayoutParams) container.getLayoutParams(); 327 | layoutParams.setMargins(containerMargin, indicatorTop - container.getHeight() + 328 | (indicatorSize / 16 * 6), containerMargin, 0); 329 | container.setLayoutParams(layoutParams); 330 | } else { 331 | // indicator looking up 332 | rotate(180); 333 | 334 | LayoutParams layoutParams = (LayoutParams) container.getLayoutParams(); 335 | layoutParams.setMargins(containerMargin, indicatorTop + 336 | (indicatorSize / 16 * 10), containerMargin, 0); 337 | container.setLayoutParams(layoutParams); 338 | } 339 | 340 | } else { 341 | 342 | Log.e("predict", "side is HORIZONTAL"); 343 | 344 | int elementRight = elementLeft + elementWidth; 345 | 346 | int indicatorVerticalCenter = elementTop + elementHeight / 2; 347 | indicatorLeft = elementLeft + elementWidth; 348 | indicatorTop = indicatorVerticalCenter - indicatorSize / 2; 349 | 350 | if (elementRight > screenWidth / 2) { 351 | 352 | // indicator looking right 353 | indicatorLeft -= (elementWidth + indicatorSize); 354 | rotate(270); 355 | 356 | int containerRight = screenWidth - indicatorLeft - (indicatorSize / 16 * 6); 357 | int containerTop = indicatorVerticalCenter - indicatorSize / 3 * 2; 358 | 359 | if (containerTop + container.getHeight() > screenHeight) 360 | containerTop -= (container.getHeight() - indicatorSize / 3 * 4); 361 | 362 | LayoutParams layoutParams = (LayoutParams) container.getLayoutParams(); 363 | layoutParams.setMargins(containerMargin, containerTop, containerRight, 0); 364 | container.setLayoutParams(layoutParams); 365 | } else { 366 | 367 | // indicator looking left 368 | rotate(90); 369 | 370 | Log.e("predict", "element is at left. ch: " + container.getHeight()); 371 | 372 | int containerLeft = indicatorLeft + indicatorSize - (indicatorSize / 16 * 6); 373 | int containerTop = indicatorVerticalCenter - indicatorSize / 3 * 2; 374 | 375 | if (containerTop + container.getHeight() > screenHeight) 376 | containerTop -= (container.getHeight() - indicatorSize / 3 * 4); 377 | 378 | LayoutParams layoutParams = (LayoutParams) container.getLayoutParams(); 379 | layoutParams.setMargins(containerLeft, containerTop, 380 | containerMargin, 0); 381 | container.setLayoutParams(layoutParams); 382 | } 383 | } 384 | 385 | LayoutParams layoutParams = (LayoutParams) indicator.getLayoutParams(); 386 | layoutParams.setMargins(indicatorLeft, indicatorTop, indicatorLeft + indicatorSize, 387 | indicatorTop + indicatorSize); 388 | indicator.setLayoutParams(layoutParams); 389 | 390 | show(); 391 | } 392 | }); 393 | } 394 | }; 395 | setSizeThread.start(); 396 | 397 | } 398 | 399 | private void showMessageInCenter() { 400 | 401 | LayoutParams layoutParams = (LayoutParams) container.getLayoutParams(); 402 | layoutParams.setMargins(containerMargin, 0, containerMargin, 0); 403 | layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT, -1); 404 | container.setLayoutParams(layoutParams); 405 | 406 | // putting indicator out of the screen 407 | // otherwise it is shown after applying animation 408 | LayoutParams layoutParams2 = (LayoutParams) indicator.getLayoutParams(); 409 | layoutParams2.setMargins(screenWidth, screenHeight, 0, 0); 410 | indicator.setLayoutParams(layoutParams2); 411 | 412 | show(); 413 | } 414 | 415 | // not working yet 416 | public void setColor(int colorCode) { 417 | //LayerDrawable cld = (LayerDrawable) container.getBackground(); 418 | //cld.get 419 | //((ShapeDrawable) container.getBackground()).getPaint().setColor(getResources().getColor(R.color.amethyst)); 420 | //LayerDrawable bgDrawable = (LayerDrawable) container.getBackground(); 421 | //final GradientDrawable shape = (GradientDrawable) bgDrawable.findDrawableByLayerId(R.id.border_radius_shape); 422 | //shape.setColor(Color.parseColor("#e67e22")); 423 | } 424 | 425 | protected void hide() { 426 | startAnimation(hideAnim); 427 | backgroundLayer.setVisibility(GONE); 428 | } 429 | 430 | protected void show() { 431 | startAnimation(showAnim); 432 | backgroundLayer.setVisibility(VISIBLE); 433 | } 434 | 435 | private void rotate(float degree) { 436 | final RotateAnimation rotateAnim = new RotateAnimation(0.0f, degree, 437 | RotateAnimation.RELATIVE_TO_SELF, 0.5f, 438 | RotateAnimation.RELATIVE_TO_SELF, 0.5f); 439 | 440 | rotateAnim.setDuration(0); 441 | rotateAnim.setFillAfter(true); 442 | indicator.startAnimation(rotateAnim); 443 | } 444 | 445 | private int getRelativeLeft(View myView) { 446 | if (myView.getParent() == myView.getRootView()) 447 | return myView.getLeft(); 448 | else 449 | return myView.getLeft() + getRelativeLeft((View) myView.getParent()); 450 | } 451 | 452 | private int getRelativeTop(View myView) { 453 | if (myView.getParent() == myView.getRootView()) 454 | return myView.getTop(); 455 | else 456 | return myView.getTop() + getRelativeTop((View) myView.getParent()); 457 | } 458 | 459 | } 460 | -------------------------------------------------------------------------------- /src/com/eluleci/appintroduction/listeners/StepActionListener.java: -------------------------------------------------------------------------------- 1 | package com.eluleci.appintroduction.listeners; 2 | 3 | /** 4 | * Created with IntelliJ IDEA. 5 | * User: eluleci 6 | * Date: 19.09.2013 7 | * Time: 23:19 8 | */ 9 | public interface StepActionListener { 10 | 11 | void beforeMessageShown(); 12 | 13 | void afterMessageShown(); 14 | } 15 | -------------------------------------------------------------------------------- /src/com/eluleci/appintroduction/listeners/UserActionListener.java: -------------------------------------------------------------------------------- 1 | package com.eluleci.appintroduction.listeners; 2 | 3 | /** 4 | * Created with IntelliJ IDEA. 5 | * User: eluleci 6 | * Date: 08.08.2013 7 | * Time: 22:29 8 | */ 9 | public interface UserActionListener { 10 | void onNextClicked(); 11 | 12 | void onDismiss(); 13 | } 14 | -------------------------------------------------------------------------------- /src/com/eluleci/appintroduction/views/DynamicDrawable.java: -------------------------------------------------------------------------------- 1 | package com.eluleci.appintroduction.views; 2 | 3 | import android.graphics.drawable.GradientDrawable; 4 | 5 | /** 6 | * Created with IntelliJ IDEA. 7 | * User: eluleci 8 | * Date: 21.10.2013 9 | * Time: 14:23 10 | */ 11 | public class DynamicDrawable extends GradientDrawable { 12 | 13 | public DynamicDrawable(int pStartColor, int pCenterColor, int pEndColor, int pStrokeWidth, int pStrokeColor, float cornerRadius) { 14 | super(Orientation.BOTTOM_TOP,new int[]{pStartColor,pCenterColor,pEndColor}); 15 | setStroke(pStrokeWidth,pStrokeColor); 16 | setShape(GradientDrawable.RECTANGLE); 17 | setCornerRadius(cornerRadius); 18 | } 19 | 20 | public DynamicDrawable(int color, float cornerRadius) { 21 | super(Orientation.BOTTOM_TOP,new int[]{color,color,color}); 22 | setStroke(1,color); 23 | setShape(GradientDrawable.RECTANGLE); 24 | setCornerRadius(cornerRadius); 25 | } 26 | } -------------------------------------------------------------------------------- /src/com/eluleci/appintroduction/views/TextViewLight.java: -------------------------------------------------------------------------------- 1 | package com.eluleci.appintroduction.views; 2 | 3 | import android.content.Context; 4 | import android.graphics.Typeface; 5 | import android.util.AttributeSet; 6 | import android.widget.TextView; 7 | 8 | /** 9 | * Created with IntelliJ IDEA. 10 | * User: eluleci 11 | * Date: 7/07/13 12 | * Time: 1:43 PM 13 | */ 14 | public class TextViewLight extends TextView { 15 | 16 | public TextViewLight(Context context, AttributeSet attrs, int defStyle) { 17 | super(context, attrs, defStyle); 18 | init(); 19 | } 20 | 21 | public TextViewLight(Context context, AttributeSet attrs) { 22 | super(context, attrs); 23 | init(); 24 | } 25 | 26 | public TextViewLight(Context context) { 27 | super(context); 28 | init(); 29 | } 30 | 31 | private void init() { 32 | Typeface tf = Typeface.createFromAsset(getContext().getAssets(), "fonts/roboto_light.ttf"); 33 | setTypeface(tf); 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /src/com/eluleci/appintroduction/views/TextViewRegular.java: -------------------------------------------------------------------------------- 1 | package com.eluleci.appintroduction.views; 2 | 3 | import android.content.Context; 4 | import android.graphics.Typeface; 5 | import android.util.AttributeSet; 6 | import android.widget.TextView; 7 | 8 | /** 9 | * Created with IntelliJ IDEA. 10 | * User: eluleci 11 | * Date: 7/07/13 12 | * Time: 1:43 PM 13 | */ 14 | public class TextViewRegular extends TextView { 15 | 16 | public TextViewRegular(Context context, AttributeSet attrs, int defStyle) { 17 | super(context, attrs, defStyle); 18 | init(); 19 | } 20 | 21 | public TextViewRegular(Context context, AttributeSet attrs) { 22 | super(context, attrs); 23 | init(); 24 | } 25 | 26 | public TextViewRegular(Context context) { 27 | super(context); 28 | init(); 29 | } 30 | 31 | private void init() { 32 | Typeface tf = Typeface.createFromAsset(getContext().getAssets(), "fonts/roboto_regular.ttf"); 33 | setTypeface(tf); 34 | } 35 | 36 | } --------------------------------------------------------------------------------