├── .gitignore
├── LICENSE
├── README.md
├── build.gradle
├── circle.yml
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── onboarder
├── .gitignore
├── build.gradle
├── gradle.properties
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── kotlin
│ └── com
│ │ └── cuneytayyildiz
│ │ └── onboarder
│ │ ├── OnboarderActivity.kt
│ │ ├── OnboarderPagerAdapter.kt
│ │ ├── model
│ │ └── OnboarderPage.kt
│ │ ├── utils
│ │ ├── Extensions.kt
│ │ ├── OnboarderPageChangeListener.kt
│ │ ├── TypefaceCacheManager.kt
│ │ └── TypefaceManager.kt
│ │ └── views
│ │ └── CircleIndicatorView.kt
│ └── res
│ ├── drawable
│ ├── ic_android_white_192dp.xml
│ ├── ic_arrow_forward_white_24dp.xml
│ ├── ic_done_white_24dp.xml
│ └── ic_right_white_24dp.xml
│ ├── layout-land
│ └── item_onboarder.xml
│ ├── layout
│ ├── activity_onboarder.xml
│ └── item_onboarder.xml
│ ├── values-h720dp
│ └── dimen.xml
│ ├── values-tr
│ └── strings.xml
│ └── values
│ ├── colors.xml
│ ├── dimen.xml
│ ├── strings.xml
│ └── styles.xml
├── sample
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── kotlin
│ └── com
│ │ └── cuneytayyildiz
│ │ └── androidonboarder
│ │ └── IntroActivity.kt
│ └── res
│ ├── drawable
│ ├── donut_circle.png
│ ├── eclair_circle.png
│ ├── froyo_circle.png
│ ├── gingerbread_circle.png
│ ├── honeycomb_circle.png
│ ├── icecream_circle.png
│ ├── jellybean_circle.png
│ ├── kitkat_circle.png
│ ├── lollipop_circle.png
│ ├── marshmallow_circle.png
│ ├── nougat_circle.png
│ ├── oreo_circle.png
│ ├── pie_circle.png
│ └── q_circle.png
│ ├── layout
│ └── activity_main.xml
│ ├── mipmap-hdpi
│ └── ic_launcher.png
│ ├── mipmap-mdpi
│ └── ic_launcher.png
│ ├── mipmap-xhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxxhdpi
│ └── ic_launcher.png
│ └── values
│ ├── colors.xml
│ ├── strings.xml
│ └── styles.xml
└── settings.gradle
/.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 | out/
15 | build/
16 |
17 | # Local configuration file (sdk path, etc)
18 | local.properties
19 |
20 | # Eclipse project files
21 | .classpath
22 | .project
23 |
24 | # Windows thumbnail db
25 | .DS_Store
26 |
27 | # IDEA/Android Studio project files, because
28 | # the project can be imported from settings.gradle
29 | .idea
30 | *.iml
31 |
32 | # Old-style IDEA project files
33 | *.ipr
34 | *.iws
35 |
36 | # Local IDEA workspace
37 | .idea/workspace.xml
38 |
39 | # Gradle cache
40 | .gradle
41 |
42 | # Sandbox stuff
43 | _sandbox
44 | /gradle.properties
45 | /upload_archives.gradle
46 | /maven_push.gradle
47 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Cuneyt AYYILDIZ
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 |
2 | []( https://android-arsenal.com/details/1/6598 )
3 |
4 | # Android Onboarder
5 |
6 | Android Onboarder is a simple and lightweight library that helps you to create cool and beautiful introduction screens for your apps without writing dozens of lines of code.
7 |
8 |
9 | * [Features](#features)
10 | * [Getting Started](#getting-started)
11 | * [Adding dependency](#adding-dependency)
12 | * [Basic usage](#basic-usage)
13 | * [Activity functions](#activity-functions)
14 | * [Page Properties](#page-properties)
15 | * [Style Modifications](#style-modifications)
16 | * [Localization](#localization)
17 | * [License](#license)
18 |
19 | 
20 |
21 | ## Features
22 |
23 | * **API >= 14** compatible.
24 | * 100% Kotlin ❤️
25 | * **AndroidX** compatible.
26 | * Support for **runtime permissions**.
27 | * Dependent only on AndroidX AppCompat/Annotations, ConstraintLayout and Kotlin JDK.
28 |
29 |
30 | ## Getting Started
31 |
32 | #### Adding dependency
33 |
34 | Add dependency in your build.gradle (app/build.gradle)
35 |
36 | ```groovy
37 | implementation 'com.cuneytayyildiz:onboarder:2.0.0'
38 | ```
39 |
40 | #### Basic usage
41 | To use Onboarder, create an activity that extends from OnboarderActivity like the following:
42 | ```kotlin
43 |
44 | class IntroActivity : OnboarderActivity(), OnboarderPageChangeListener {
45 | override fun onCreate(savedInstanceState: Bundle?) {
46 | super.onCreate(savedInstanceState)
47 | setOnboarderPageChangeListener(this)
48 |
49 | val pages: MutableList = createOnboarderPages()
50 |
51 | initOnboardingPages(pages)
52 | }
53 |
54 | public override fun onSkipButtonPressed() {
55 | super.onSkipButtonPressed()
56 | Toast.makeText(this, "Skip button was pressed!", Toast.LENGTH_SHORT).show()
57 | }
58 |
59 | override fun onFinishButtonPressed() {
60 | // implement your logic, save induction has done to sharedPrefs
61 | Toast.makeText(this, "Finish button was pressed", Toast.LENGTH_SHORT).show()
62 | }
63 |
64 | override fun onPageChanged(position: Int) {
65 | Log.d(javaClass.simpleName, "onPageChanged: $position")
66 | }
67 |
68 | private fun createOnboarderPages(): MutableList {
69 | return mutableListOf(
70 | onboarderPage {
71 | backgroundColor = color(R.color.color_donut)
72 |
73 | image {
74 | imageResId = R.drawable.donut_circle
75 | }
76 |
77 | title {
78 | text = "Donut"
79 | textColor = color(R.color.primary_text)
80 | }
81 |
82 | description {
83 | text = "Version 1.6 Donut was given the name Donut. "
84 | textColor = color(R.color.secondary_text)
85 | multilineCentered = true
86 | }
87 | },
88 | onboarderPage {
89 | backgroundColor = color(R.color.color_android_green)
90 |
91 | image {
92 | imageResId = R.drawable.q_circle
93 | }
94 |
95 | title {
96 | text = "Q"
97 | textColor = color(R.color.primary_text)
98 | }
99 |
100 | description {
101 | text = "Android 10 was officially released on September 3, 2019 for supported Google Pixel devices.\n" +
102 | "\nGoogle announced that a new Android Version will be officially known as Android 10."
103 | textColor = color(R.color.secondary_text)
104 | multilineCentered = true
105 | }
106 |
107 | miscellaneousButton {
108 | visibility = View.VISIBLE
109 | text = "What's Next?"
110 | backgroundColor = Color.WHITE
111 | textColor = color(R.color.color_android_green)
112 | clickListener = View.OnClickListener {
113 | Toast.makeText(this@IntroActivity, "Hello World", Toast.LENGTH_SHORT).show()
114 | }
115 | }
116 | }
117 | )
118 | }
119 | }
120 | ```
121 |
122 | #### Activity functions
123 |
124 | ```kotlin
125 | /*********** Activity methods ***********/
126 | fun initOnboardingPages(pages: MutableList) // Set onboarding pages into adapter
127 | fun setPageTransformer(pageTransformer: ViewPager.PageTransformer) // Animate your page transitions
128 | fun setOnboarderPageChangeListener(onboarderPageChangeListener: OnboarderPageChangeListener?) // Get current position of the page
129 |
130 | fun setInactiveIndicatorColor(color: Int) // Change dot's color for inactive status
131 | fun setActiveIndicatorColor(color: Int) // Change dot's color for active status
132 |
133 | fun setDividerColor(@ColorInt color: Int) // Set divider color
134 | fun setDividerHeight(heightInDp: Int) // Set divider height
135 | fun setDividerVisibility(dividerVisibility: Int) // Hide divider
136 |
137 | fun shouldUseFloatingActionButton(shouldUseFloatingActionButton: Boolean) // Change skip and finish button as FloatingActionButton aka FAB
138 |
139 | fun shouldDarkenButtonsLayout(shouldDarkenButtonsLayout: Boolean) // Make buttons layout darker on bottom
140 |
141 | fun setSkipButtonHidden() // Hide skip button
142 | fun setSkipButtonTitle(title: CharSequence?) // Set custom text for skip button
143 | fun setSkipButtonTitle(@StringRes titleResId: Int)
144 | fun setSkipButtonTextColor(@ColorRes colorResId: Int)
145 | fun setSkipButtonBackgroundColor(@ColorRes colorResId: Int)
146 |
147 | fun setFinishButtonTitle(title: CharSequence?) // Set custom text for finish button
148 | fun setFinishButtonTitle(@StringRes titleResId: Int)
149 | fun setFinishButtonTextColor(@ColorRes colorResId: Int)
150 | fun setFinishButtonBackgroundColor(@ColorRes colorResId: Int)
151 |
152 | fun setNextButtonTitle(title: CharSequence?) // Set custom text for next button
153 | fun setNextButtonTitle(@StringRes titleResId: Int)
154 | fun setNextButtonTextColor(@ColorRes colorResId: Int)
155 | fun setNextButtonBackgroundColor(@ColorRes colorResId: Int)
156 | fun setNextButtonIcon(@DrawableRes drawableResId: Int)
157 |
158 | fun NextButton() // Get Next button to change it's properties
159 | fun SkipButton() // Get Skip button to change it's properties
160 | fun FinishButton() // Get Finish button to change it's properties
161 | fun FabButton() // Get Fab button to change it's properties
162 | ```
163 |
164 | #### Page Properties
165 | You can change most properties of the views on page such as background color, text size, text color, showing a button, setting a click listener to view etc.
166 | ```kotlin
167 | data class OnboarderPage(
168 | backgroundColor // Background color of the page
169 | image: OnboarderImage // Thumbnail image at top
170 | title: OnboarderText // Title of the page
171 | description: OnboarderText // Description text
172 | miscellaneousButton: OnboarderMiscellaneousButton // A button where you can add any functionality that you want. Request a permission, show recent changes of your app, start your privacy policy url etc.
173 | )
174 |
175 | data class OnboarderImage(
176 | imageResId // R.drawable.first_page_thumbnail
177 | drawable // ContextCompat.getDrawable(context, R.drawable.first_page_thumbnail)
178 | imageWidthPx // ViewGroup.LayoutParams.WRAP_CONTENT, 100.dp, 100.px
179 | imageHeightPx // ViewGroup.LayoutParams.WRAP_CONTENT, 100.dp, 100.px
180 | imageBias // .5f (0 is top, 1 is bottom)
181 | )
182 |
183 | data class OnboarderText(
184 | text // "First Page Title"
185 | textResId // R.string.first_page_title
186 | textColor // color(R.color.first_page_title_color)
187 | backgroundColor // color(R.color.first_page_title_background_color)
188 | widthPx // ViewGroup.LayoutParams.WRAP_CONTENT, 100.dp, 100.px
189 | heightPx // ViewGroup.LayoutParams.WRAP_CONTENT, 100.dp, 100.px
190 | typefacePath // fonts/myfont.ttf
191 | typefaceFontResId // R.font.my_font
192 | textSize // 20f
193 | textPaddingBottomPx // 20
194 | multilineCentered // true, false
195 | clickListener // View.OnClickListener{ textView -> }
196 | )
197 |
198 | data class OnboarderMiscellaneousButton(
199 | visibility // default View.GONE,
200 | text // Button text
201 | textResId // R.string.button_text
202 | textColor // color(R.color.button_text_color)
203 | backgroundColor // color(R.color.button_background_color)
204 | widthPx // ViewGroup.LayoutParams.WRAP_CONTENT, 100.dp, 100.px
205 | heightPx // ViewGroup.LayoutParams.WRAP_CONTENT, 100.dp, 100.px
206 | typefacePath // fonts/myfont.ttf
207 | typefaceFontResId // R.font.my_font
208 | textSize // 20f
209 | leftPadding // 16,
210 | rightPadding // 16,
211 | topPadding // 8,
212 | bottomPadding // 8
213 | clickListener // View.OnClickListener{ button -> }
214 | )
215 | ```
216 |
217 | #### Style modifications
218 | If you would like to change style on the OnboarderPage, you can simple add these styles in your app/res/values/styles.xml and change the attributes.
219 |
220 | ```xml
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 | ```
229 |
230 | #### Localization
231 | To localize buttons from the library to your language, add these strings into corresponding app/res/values-XX/strings.xml
232 | ```xml
233 |
234 |
235 | ...
236 | ...
237 | ...
238 |
239 | ```
240 | or
241 | ```kotlin
242 | SkipButton().setText(R.string.onboarder_button_skip)
243 | NextButton().setText(R.string.onboarder_button_next)
244 | FinishButton().setText(R.string.onboarder_button_finish)
245 | ```
246 |
247 |
248 | ## License
249 |
250 | ```
251 | MIT License
252 |
253 | Copyright (c) 2017 Cuneyt AYYILDIZ
254 |
255 | Permission is hereby granted, free of charge, to any person obtaining a copy
256 | of this software and associated documentation files (the "Software"), to deal
257 | in the Software without restriction, including without limitation the rights
258 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
259 | copies of the Software, and to permit persons to whom the Software is
260 | furnished to do so, subject to the following conditions:
261 |
262 | The above copyright notice and this permission notice shall be included in all
263 | copies or substantial portions of the Software.
264 |
265 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
266 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
267 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
268 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
269 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
270 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
271 | SOFTWARE.
272 |
273 | ```
274 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.3.72'
3 |
4 | repositories {
5 | google()
6 | mavenCentral()
7 | jcenter()
8 | maven {
9 | url "https://maven.google.com"
10 | }
11 | }
12 | dependencies {
13 | classpath 'com.android.tools.build:gradle:4.0.0-rc01'
14 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
15 | }
16 | }
17 |
18 | allprojects {
19 | tasks.withType(Javadoc).all { enabled = false }
20 |
21 | repositories {
22 | google()
23 | jcenter()
24 | maven {
25 | url "https://maven.google.com"
26 | }
27 | }
28 | }
29 |
30 |
--------------------------------------------------------------------------------
/circle.yml:
--------------------------------------------------------------------------------
1 | machine:
2 | environment:
3 | GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError"'
4 | JAVA_OPTS: "-Xms512m -Xmx2048m"
5 | ANDROID_HOME: /usr/local/android-sdk-linux
6 | TERM: "dumb"
7 | java:
8 | version: oraclejdk8
9 | dependencies:
10 | pre:
11 | - echo y | android update sdk --no-ui --all --filter tools,platform-tools,build-tools-26.0.1,android-26,extra-google-m2repository,extra-google-google_play_services,extra-android-support,extra-android-m2repository
12 | cache_directories:
13 | - /usr/local/android-sdk-linux/platforms/android-26
14 | - /usr/local/android-sdk-linux/build-tools/26.0.1
15 | - /usr/local/android-sdk-linux/extras/android/m2repository
16 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Swisyn/Android-Onboarder/8ac8870cc121316c9b40e42fd7a45b4bb31408a7/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri May 15 23:12:44 CEST 2020
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/onboarder/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/onboarder/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'kotlin-android-extensions'
4 |
5 | android {
6 | compileSdkVersion 29
7 |
8 | defaultConfig {
9 | minSdkVersion 14
10 | targetSdkVersion 29
11 | versionCode 1
12 | versionName "1.0"
13 | vectorDrawables.useSupportLibrary = true
14 | }
15 | buildTypes {
16 | release {
17 | minifyEnabled false
18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
19 | }
20 | debug {
21 | minifyEnabled false
22 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
23 | }
24 | }
25 | lintOptions {
26 | abortOnError false
27 | }
28 | sourceSets {
29 | main.java.srcDirs += 'src/main/kotlin'
30 | }
31 | }
32 |
33 | dependencies {
34 | implementation "androidx.core:core-ktx:1.2.0"
35 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
36 |
37 | implementation 'androidx.appcompat:appcompat:1.1.0'
38 | implementation 'com.google.android.material:material:1.2.0-alpha06'
39 | implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta6'
40 |
41 | }
42 | apply from: '../maven_push.gradle'
43 |
--------------------------------------------------------------------------------
/onboarder/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_NAME=AndroidOnboarder
2 | POM_ARTIFACT_ID=onboarder
3 | POM_PACKAGING=aar
--------------------------------------------------------------------------------
/onboarder/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/Blackmagic/Library/Android/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 |
--------------------------------------------------------------------------------
/onboarder/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/onboarder/src/main/kotlin/com/cuneytayyildiz/onboarder/OnboarderActivity.kt:
--------------------------------------------------------------------------------
1 | package com.cuneytayyildiz.onboarder
2 |
3 | import android.animation.ArgbEvaluator
4 | import android.graphics.Color
5 | import android.os.Build
6 | import android.os.Bundle
7 | import android.util.TypedValue
8 | import android.view.View
9 | import android.widget.Button
10 | import android.widget.FrameLayout
11 | import androidx.annotation.ColorInt
12 | import androidx.annotation.ColorRes
13 | import androidx.annotation.DrawableRes
14 | import androidx.annotation.StringRes
15 | import androidx.appcompat.app.AppCompatActivity
16 | import androidx.core.content.ContextCompat
17 | import androidx.viewpager.widget.ViewPager
18 | import androidx.viewpager.widget.ViewPager.OnPageChangeListener
19 | import com.cuneytayyildiz.onboarder.model.OnboarderPage
20 | import com.cuneytayyildiz.onboarder.utils.*
21 | import com.cuneytayyildiz.onboarder.views.CircleIndicatorView
22 | import com.google.android.material.floatingactionbutton.FloatingActionButton
23 |
24 | abstract class OnboarderActivity : AppCompatActivity(R.layout.activity_onboarder), View.OnClickListener, OnPageChangeListener {
25 | private lateinit var circleIndicatorView: CircleIndicatorView
26 | private lateinit var viewPagerOnboarder: ViewPager
27 | private lateinit var btnSkip: Button
28 | private lateinit var btnFinish: Button
29 | private lateinit var btnNext: Button
30 | private lateinit var buttonsLayout: FrameLayout
31 | private lateinit var fab: FloatingActionButton
32 | private lateinit var divider: View
33 |
34 | private lateinit var onboarderAdapter: OnboarderPagerAdapter
35 |
36 | private var backgroundColors: Array? = null
37 |
38 | private var evaluator: ArgbEvaluator = ArgbEvaluator()
39 | private var shouldDarkenButtonsLayout = false
40 | private var shouldUseFloatingActionButton = false
41 | private var onboarderPageChangeListener: OnboarderPageChangeListener? = null
42 |
43 | override fun onCreate(savedInstanceState: Bundle?) {
44 | super.onCreate(savedInstanceState)
45 |
46 | initViews()
47 | }
48 |
49 | private fun initViews() {
50 | supportActionBar?.hide()
51 |
52 | setStatusBackgroundColor()
53 |
54 | circleIndicatorView = findViewById(R.id.indicator_circle)
55 | btnNext = findViewById(R.id.button_next)
56 | btnSkip = findViewById(R.id.button_skip)
57 | btnFinish = findViewById(R.id.button_finish)
58 | buttonsLayout = findViewById(R.id.layout_buttons)
59 | fab = findViewById(R.id.fab)
60 | divider = findViewById(R.id.divider)
61 | viewPagerOnboarder = findViewById(R.id.viewpager_onboarder)
62 |
63 | viewPagerOnboarder.addOnPageChangeListener(this)
64 | btnNext.setOnClickListener(this)
65 | btnSkip.setOnClickListener(this)
66 | btnFinish.setOnClickListener(this)
67 | fab.setOnClickListener(this)
68 | }
69 |
70 | fun initOnboardingPages(pages: MutableList) {
71 | backgroundColors = getPageBackgroundColors(pages)
72 |
73 | onboarderAdapter = OnboarderPagerAdapter(this, pages)
74 | viewPagerOnboarder.adapter = onboarderAdapter
75 | circleIndicatorView.setPageIndicatorCount(pages.size)
76 | }
77 |
78 | private fun darkenColor(@ColorInt color: Int): Int {
79 | val hsv = FloatArray(3)
80 | Color.colorToHSV(color, hsv)
81 | hsv[2] *= 0.9f
82 | return Color.HSVToColor(hsv)
83 | }
84 |
85 | private fun setStatusBackgroundColor() {
86 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
87 | window.decorView.systemUiVisibility = (
88 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
89 | or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
90 | window.statusBarColor = ContextCompat.getColor(this, R.color.black_transparent)
91 | }
92 | }
93 |
94 | override fun onClick(view: View) {
95 | val viewId = view.id
96 |
97 | if (::onboarderAdapter.isInitialized) {
98 | val isInLastPage = viewPagerOnboarder.currentItem == onboarderAdapter.lastPosition
99 |
100 | when {
101 | viewId == R.id.button_next || viewId == R.id.fab && !isInLastPage -> {
102 | viewPagerOnboarder.currentItem = viewPagerOnboarder.currentItem + 1
103 | }
104 | viewId == R.id.button_skip -> {
105 | onSkipButtonPressed()
106 | }
107 | viewId == R.id.button_finish || viewId == R.id.fab && isInLastPage -> {
108 | onFinishButtonPressed()
109 | }
110 | }
111 | }
112 | }
113 |
114 | override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
115 | if (::onboarderAdapter.isInitialized && backgroundColors != null) {
116 | val colors = backgroundColors!!
117 |
118 | if (position < onboarderAdapter.lastPosition && position < colors.size - 1) {
119 | viewPagerOnboarder.setBackgroundColor((evaluator.evaluate(positionOffset, colors[position], colors[position + 1]) as Int))
120 |
121 | if (shouldDarkenButtonsLayout) {
122 | buttonsLayout.setBackgroundColor(darkenColor(evaluator.evaluate(positionOffset, colors[position], colors[position + 1]) as Int))
123 | divider.gone()
124 | }
125 | } else {
126 | viewPagerOnboarder.setBackgroundColor(colors[colors.size - 1])
127 |
128 | if (shouldDarkenButtonsLayout) {
129 | buttonsLayout.setBackgroundColor(darkenColor(colors[colors.size - 1]))
130 | divider.gone()
131 | }
132 | }
133 | }
134 | }
135 |
136 | override fun onPageSelected(position: Int) {
137 | if (::onboarderAdapter.isInitialized) {
138 | circleIndicatorView.setCurrentPage(position)
139 |
140 | val isLastPage = (position == onboarderAdapter.lastPosition)
141 |
142 | if (shouldUseFloatingActionButton) {
143 | fab.setImageResource(if (isLastPage) R.drawable.ic_done_white_24dp else R.drawable.ic_arrow_forward_white_24dp)
144 | } else {
145 | if (isLastPage) {
146 | btnNext.gone()
147 | btnFinish.visible()
148 | } else {
149 | btnFinish.gone()
150 | btnNext.visible()
151 | }
152 | }
153 |
154 | onboarderPageChangeListener?.onPageChanged(position)
155 | }
156 | }
157 |
158 | override fun onPageScrollStateChanged(state: Int) {}
159 |
160 | protected open fun onSkipButtonPressed() {
161 | if (::onboarderAdapter.isInitialized) {
162 | viewPagerOnboarder.currentItem = onboarderAdapter.count
163 | }
164 | }
165 |
166 | abstract fun onFinishButtonPressed()
167 |
168 | protected fun setPage(position: Int) {
169 | viewPagerOnboarder.currentItem = position
170 | }
171 |
172 | fun setInactiveIndicatorColor(color: Int) {
173 | circleIndicatorView.setInactiveIndicatorColor(color)
174 | }
175 |
176 | fun setActiveIndicatorColor(color: Int) {
177 | circleIndicatorView.setActiveIndicatorColor(color)
178 | }
179 |
180 | fun shouldDarkenButtonsLayout(shouldDarkenButtonsLayout: Boolean) {
181 | this.shouldDarkenButtonsLayout = shouldDarkenButtonsLayout
182 | }
183 |
184 | fun setDividerColor(@ColorInt color: Int) {
185 | if (!shouldDarkenButtonsLayout) divider.setBackgroundColor(color)
186 | }
187 |
188 | fun setDividerHeight(heightInDp: Int) {
189 | if (!shouldDarkenButtonsLayout) divider.layoutParams.height = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, heightInDp.toFloat(),
190 | resources.displayMetrics).toInt()
191 | }
192 |
193 | fun setDividerVisibility(dividerVisibility: Int) {
194 | divider.visibility = dividerVisibility
195 | }
196 |
197 | fun setOnboarderPageChangeListener(onboarderPageChangeListener: OnboarderPageChangeListener?) {
198 | this.onboarderPageChangeListener = onboarderPageChangeListener
199 | }
200 |
201 | fun shouldUseFloatingActionButton(shouldUseFloatingActionButton: Boolean) {
202 | this.shouldUseFloatingActionButton = shouldUseFloatingActionButton
203 |
204 | if (shouldUseFloatingActionButton) {
205 | fab.visible()
206 | setDividerVisibility(View.GONE)
207 | shouldDarkenButtonsLayout(false)
208 | btnFinish.gone()
209 | btnSkip.gone()
210 | btnNext.gone()
211 | btnNext.isFocusable = false
212 | buttonsLayout.layoutParams.height = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 96f,
213 | resources.displayMetrics).toInt()
214 | }
215 | }
216 |
217 | fun setPageTransformer(pageTransformer: ViewPager.PageTransformer) {
218 | viewPagerOnboarder.setPageTransformer(true, pageTransformer)
219 | }
220 |
221 |
222 | fun setSkipButtonTitle(title: CharSequence?) {
223 | btnSkip.text = title
224 | }
225 |
226 | fun setSkipButtonHidden() {
227 | btnSkip.gone()
228 | }
229 |
230 | fun setSkipButtonTitle(@StringRes titleResId: Int) {
231 | btnSkip.setText(titleResId)
232 | }
233 |
234 | fun setFinishButtonTitle(title: CharSequence?) {
235 | btnFinish.text = title
236 | }
237 |
238 | fun setFinishButtonTitle(@StringRes titleResId: Int) {
239 | btnFinish.setText(titleResId)
240 | }
241 |
242 | fun setFinishButtonTextColor(@ColorRes colorResId: Int) {
243 | btnFinish.setTextColor(color(colorResId))
244 | }
245 |
246 | fun setNextButtonTextColor(@ColorRes colorResId: Int) {
247 | btnNext.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0)
248 | btnNext.setTextColor(color(colorResId))
249 | }
250 |
251 | fun setSkipButtonTextColor(@ColorRes colorResId: Int) {
252 | btnSkip.setTextColor(color(colorResId))
253 | }
254 |
255 | fun setFinishButtonBackgroundColor(@ColorRes colorResId: Int) {
256 | btnFinish.setBackgroundColor(color(colorResId))
257 | }
258 |
259 | fun setSkipButtonBackgroundColor(@ColorRes colorResId: Int) {
260 | btnSkip.setBackgroundColor(color(colorResId))
261 | }
262 |
263 | fun setNextButtonBackgroundColor(@ColorRes colorResId: Int) {
264 | btnNext.setBackgroundColor(color(colorResId))
265 | }
266 |
267 | fun setNextButtonTitle(title: CharSequence?) {
268 | btnNext.text = title
269 | btnNext.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0)
270 | }
271 |
272 | fun setNextButtonTitle(@StringRes titleResId: Int) {
273 | btnNext.setText(titleResId)
274 | btnNext.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0)
275 | }
276 |
277 | fun setNextButtonIcon(@DrawableRes drawableResId: Int) {
278 | btnNext.text = null
279 | btnNext.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, drawableResId)
280 | }
281 |
282 | fun NextButton() = btnNext
283 |
284 | fun SkipButton() = btnSkip
285 |
286 | fun FinishButton() = btnFinish
287 |
288 | fun FabButton() = fab
289 |
290 | private fun getPageBackgroundColors(pages: MutableList): Array {
291 | return pages.map { page -> page.backgroundColor }.toTypedArray()
292 | }
293 | }
--------------------------------------------------------------------------------
/onboarder/src/main/kotlin/com/cuneytayyildiz/onboarder/OnboarderPagerAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.cuneytayyildiz.onboarder
2 |
3 | import android.content.Context
4 | import android.view.Gravity
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import android.widget.Button
9 | import android.widget.FrameLayout
10 | import android.widget.ImageView
11 | import android.widget.TextView
12 | import androidx.constraintlayout.widget.ConstraintLayout
13 | import androidx.viewpager.widget.PagerAdapter
14 | import com.cuneytayyildiz.onboarder.model.OnboarderImage
15 | import com.cuneytayyildiz.onboarder.model.OnboarderMiscellaneousButton
16 | import com.cuneytayyildiz.onboarder.model.OnboarderPage
17 | import com.cuneytayyildiz.onboarder.model.OnboarderText
18 | import com.cuneytayyildiz.onboarder.utils.TypefaceManager
19 | import com.cuneytayyildiz.onboarder.utils.px
20 |
21 | class OnboarderPagerAdapter(private val context: Context, private val onboarderPages: MutableList) : PagerAdapter() {
22 |
23 | override fun getCount(): Int = onboarderPages.size
24 |
25 | override fun isViewFromObject(view: View, obj: Any): Boolean = view == obj
26 |
27 | fun getItem(position: Int) = onboarderPages[position]
28 |
29 | override fun instantiateItem(container: ViewGroup, position: Int): Any {
30 | val itemView = LayoutInflater.from(context).inflate(R.layout.item_onboarder, container, false)
31 |
32 | val onboarderImageView = itemView.findViewById(R.id.image_top)
33 | val onboarderTitleTextView = itemView.findViewById(R.id.textview_title)
34 | val onboarderDescriptionTextView = itemView.findViewById(R.id.textview_description)
35 | val onboarderMiscellaneousButton = itemView.findViewById