├── .github
├── FUNDING.yml
├── dependabot.yml
└── workflows
│ └── android.yml
├── .gitignore
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── assets
│ ├── Lato-Light.ttf
│ ├── Lato-Regular.ttf
│ ├── OpenSans-Light.ttf
│ ├── OpenSans-Regular.ttf
│ └── nemoy_medium.ttf
│ ├── ic_launcher-playstore.png
│ ├── java
│ └── com
│ │ └── limurse
│ │ └── onboarding
│ │ └── IntroActivity.kt
│ └── res
│ ├── drawable
│ ├── back_slide1.xml
│ ├── back_slide2.xml
│ ├── back_slide3.xml
│ ├── back_slide4.xml
│ ├── back_slide5.xml
│ ├── first.jpg
│ ├── ic_launcher_foreground.xml
│ ├── ic_slide1.png
│ ├── ic_slide2.png
│ ├── ic_slide3.png
│ ├── ic_slide4.png
│ ├── metabrainz.png
│ ├── second.jpg
│ └── third.jpg
│ ├── font
│ ├── lato.xml
│ └── opensans_regular.ttf
│ ├── mipmap-anydpi-v26
│ ├── ic_launcher.xml
│ └── ic_launcher_round.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-mdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── raw
│ ├── location.json
│ ├── music.json
│ ├── rocket.json
│ ├── teen.json
│ └── trophy.json
│ └── values
│ ├── colors.xml
│ ├── font_certs.xml
│ ├── ic_launcher_background.xml
│ ├── preloaded_fonts.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── jitpack.yml
├── local.properties
├── onboard
├── build.gradle
├── consumer-proguard-rules.pro
├── gradle.properties
└── src
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── limurse
│ │ │ └── onboard
│ │ │ ├── OnboardAdvanced.kt
│ │ │ ├── OnboardBase.kt
│ │ │ ├── OnboardBaseFragment.kt
│ │ │ ├── OnboardCustomLayoutFragment.kt
│ │ │ ├── OnboardFragment.kt
│ │ │ ├── OnboardLegacy.kt
│ │ │ ├── OnboardPageTransformerType.kt
│ │ │ ├── OnboardViewPagerListener.kt
│ │ │ ├── SlideBackgroundColorHolder.kt
│ │ │ ├── SlidePolicy.kt
│ │ │ ├── SlideSelectionListener.kt
│ │ │ ├── indicator
│ │ │ ├── DotIndicatorController.kt
│ │ │ ├── IndicatorController.kt
│ │ │ └── ProgressIndicatorController.kt
│ │ │ ├── internal
│ │ │ ├── CustomFontCache.kt
│ │ │ ├── LayoutUtil.kt
│ │ │ ├── LogHelper.kt
│ │ │ ├── OnboardViewPager.kt
│ │ │ ├── PermissionWrapper.kt
│ │ │ ├── ScrollerCustomDuration.kt
│ │ │ ├── TypefaceContainer.kt
│ │ │ └── viewpager
│ │ │ │ ├── PagerAdapter.kt
│ │ │ │ └── ViewPagerTransformer.kt
│ │ │ └── model
│ │ │ ├── SliderPage.kt
│ │ │ └── SliderPagerBuilder.kt
│ └── res
│ │ ├── drawable-v21
│ │ └── ic_onboard_ripple.xml
│ │ ├── drawable
│ │ ├── ic_onboard_arrow.xml
│ │ ├── ic_onboard_done.xml
│ │ ├── ic_onboard_fab_background.xml
│ │ ├── ic_onboard_fab_done.xml
│ │ ├── ic_onboard_fab_next.xml
│ │ ├── ic_onboard_fab_selected.xml
│ │ ├── ic_onboard_fab_skip.xml
│ │ ├── ic_onboard_indicator.xml
│ │ ├── ic_onboard_next.xml
│ │ ├── ic_onboard_ripple.xml
│ │ ├── ic_onboard_skip.xml
│ │ └── rounded_button.xml
│ │ ├── layout-land
│ │ └── onboard_fragment_intro.xml
│ │ ├── layout
│ │ ├── onboard_fragment_intro.xml
│ │ ├── onboard_intro_layout.xml
│ │ └── onboard_intro_layout2.xml
│ │ ├── raw
│ │ └── compass.json
│ │ ├── values-my
│ │ ├── values-sw600dp
│ │ └── dimen-sw600dp.xml
│ │ ├── values-v21
│ │ └── styles.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimen.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── limurse
│ └── onboard
│ ├── internal
│ └── LogHelperTest.kt
│ └── model
│ ├── SliderPageBuilderTest.kt
│ └── SliderPageTest.kt
└── settings.gradle
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: akshaaatt
4 | patreon: akshaaatt
5 | custom: https://paypal.me/akshaaatt
6 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | # Updates for Github Actions used in the repo
4 | - package-ecosystem: "github-actions"
5 | directory: "/"
6 | target-branch: "master"
7 | schedule:
8 | interval: "weekly"
9 | day: "wednesday"
10 | time: "00:00"
11 |
12 | # Updates for Gradle dependencies used in the app
13 | - package-ecosystem: "gradle"
14 | directory: "/"
15 | target-branch: "master"
16 | schedule:
17 | interval: "weekly"
18 | day: "wednesday"
19 | time: "00:00"
20 | open-pull-requests-limit: 10
21 |
--------------------------------------------------------------------------------
/.github/workflows/android.yml:
--------------------------------------------------------------------------------
1 | name: Android CI
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ master ]
8 |
9 | jobs:
10 | build:
11 | runs-on: ubuntu-latest
12 |
13 | steps:
14 | - uses: actions/checkout@v4
15 |
16 | - name: set up JDK
17 | uses: actions/setup-java@v4
18 | with:
19 | distribution: 'oracle'
20 | java-version: 17
21 |
22 | - name: Grant execute permission for gradlew
23 | run: chmod +x gradlew
24 |
25 | - name: Run unit tests
26 | run: ./gradlew test
27 |
28 | - name: Build with Gradle
29 | run: ./gradlew build
30 |
31 | - name: Run lint with Gradle
32 | run: ./gradlew lint
33 |
34 | - name: Check lint results
35 | uses: yutailang0119/action-android-lint@v3
36 | with:
37 | report-path: build/reports/*.xml
38 | continue-on-error: false
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the ART/Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 | out/
15 |
16 | # Gradle files
17 | .gradle/
18 | build/
19 |
20 | # Local configuration file (sdk path, etc)
21 | local.properties
22 |
23 | # Proguard folder generated by Eclipse
24 | proguard/
25 |
26 | # Log Files
27 | *.log
28 |
29 | # Android Studio Navigation editor temp files
30 | .navigation/
31 |
32 | # Android Studio captures folder
33 | captures/
34 |
35 | # Intellij
36 | *.iml
37 | .idea
38 |
39 | # Keystore files
40 | *.jks
41 |
42 | # External native build folder generated in Android Studio 2.2 and later
43 | .externalNativeBuild
44 |
45 |
46 | # Freeline
47 | freeline.py
48 | freeline/
49 | freeline_project_description.json
50 | .DS_Store
51 | app/.DS_Store
52 | app/src/.DS_Store
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
Onboarding
2 |
3 |
4 |
5 |
6 |
8 |
9 |
11 |
12 |
14 |
15 |
16 |
17 | Features •
18 | Contribution
19 |
20 |
21 | [](https://postimg.cc/zycyTyg9)
22 | [](https://postimg.cc/Q9b990kq)
23 |
24 | Onboarder is an Android library for easing up the onboarding process to Apps.
25 |
26 | ## Features
27 |
28 | * Written in Kotlin
29 | * No boilerplate code
30 | * Easy initialization
31 | * Supports Lottie Animation View and Images with a Title and Description.
32 |
33 | ## Gradle Dependency
34 |
35 | * Add the JitPack repository to your project's build.gradle file
36 |
37 | ```groovy
38 | allprojects {
39 | repositories {
40 | ...
41 | maven { url 'https://jitpack.io' }
42 | }
43 | }
44 | ```
45 |
46 | * Add the dependency in your app's build.gradle file
47 |
48 | ```groovy
49 | dependencies {
50 | implementation 'com.github.akshaaatt:Onboarding:1.1.3'
51 | }
52 | ```
53 |
54 | ## Basic usage
55 |
56 | To use Onboarder, you simply have to create a new Activity that extends OnboardAdvanced or OnboardLegacy like the following:
57 |
58 | ```kotlin
59 | class MyCustomOnboarder : OnboardAdvanced() {
60 | override fun onCreate(savedInstanceState: Bundle?) {
61 | super.onCreate(savedInstanceState)
62 | // Make sure you don't call setContentView!
63 |
64 | // Call addSlide passing your Fragments.
65 | // You can use OnboardFragment to use a pre-built fragment
66 | addSlide(OnboardFragment.newInstance(
67 | title = "Welcome...",
68 | description = "This is the first slide of the example"
69 | ))
70 | addSlide(OnboardFragment.newInstance(
71 | title = "...Let's get started!",
72 | description = "This is the last slide, I won't annoy you more :)"
73 | ))
74 | }
75 |
76 | override fun onSkipPressed(currentFragment: Fragment?) {
77 | super.onSkipPressed(currentFragment)
78 | // Decide what to do when the user clicks on "Skip"
79 | finish()
80 | }
81 |
82 | override fun onDonePressed(currentFragment: Fragment?) {
83 | super.onDonePressed(currentFragment)
84 | // Decide what to do when the user clicks on "Done"
85 | finish()
86 | }
87 | }
88 | ```
89 |
90 | Please note that you must NOT call setContentView. The OnboardAdvanced superclass is taking care of it for you.
91 |
92 | Also confirm that you're overriding onCreate with a single parameter (Bundle) and you're not using another override (like onCreate(Bundle, PersistableBundle)) instead.
93 |
94 | Finally, declare the activity in your Manifest like so:
95 |
96 | ``` xml
97 |
99 | ```
100 |
101 | We suggest to don't declare MyCustomOnboard as your first Activity unless you want the intro to launch every time your app starts. Ideally you should show the OnboardAdvanced activity only once to the user, and you should hide it once completed (you can use a flag in the SharedPreferences).
102 |
103 | ## Creating Slides 👩🎨
104 |
105 | The entry point to add a new slide is the `addSlide(fragment: Fragment)` function on the `OnboardAdvanced` or `OnboardLegacy` class.
106 | You can easily use it to add a new `Fragment` to the carousel.
107 |
108 | The library comes with several util classes to help you create your Slide with just a couple lines:
109 |
110 | ### `OnboardFragment`
111 |
112 | You can use the `OnboardFragment` if you just want to customize title, description, image and colors.
113 | That's the suggested approach if you want to create a quick intro:
114 |
115 | ```kotlin
116 | addSlide(OnboardFragment.newInstance(
117 | title = "The title of your slide",
118 | description = "A description that will be shown on the bottom",
119 | resourceId = R.drawable.the_central_icon, //or R.raw.your_json for LottieAnimationView
120 | backgroundDrawable = R.drawable.the_background_image,
121 | titleColor = Color.YELLOW,
122 | descriptionColor = Color.RED,
123 | backgroundColor = Color.BLUE,
124 | titleTypefaceFontRes = R.font.opensans_regular,
125 | descriptionTypefaceFontRes = R.font.opensans_regular,
126 | isLottie = true //To hide the imageView and enable the LottieAnimationView
127 | ))
128 | ```
129 |
130 | All the parameters are optional, so you're free to customize your slide as you wish.
131 |
132 | If you need to programmatically create several slides you can also use the `SliderPage` class.
133 | This class can be passed to `OnboardFragment.newInstance(sliderPage: SliderPage)` that will create
134 | a new slide starting from that instance.
135 |
136 | #### Refer the sample code provided in this repository.
137 |
138 | #### Inspired by [AppIntro](https://github.com/AppIntro/AppIntro)
139 |
140 | ## Contribution
141 |
142 | You are most welcome to contribute to this project!
143 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'kotlin-android'
4 | }
5 |
6 | android {
7 | namespace 'com.limurse.onboarding'
8 |
9 | compileSdk 34
10 | defaultConfig {
11 | applicationId "com.limurse.onboarding"
12 | minSdk 17
13 | targetSdk 34
14 | versionCode 1
15 | versionName "1.0"
16 | }
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 |
24 | compileOptions {
25 | sourceCompatibility JavaVersion.VERSION_17
26 | targetCompatibility JavaVersion.VERSION_17
27 | }
28 | kotlinOptions {
29 | jvmTarget = '17'
30 | }
31 | }
32 |
33 | dependencies {
34 | implementation project(':onboard')
35 |
36 | implementation 'androidx.appcompat:appcompat:1.6.1'
37 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/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 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/assets/Lato-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akshaaatt/Onboarding-Android/e5c7187a9fdc99a03621a0df1bf00f875e34388c/app/src/main/assets/Lato-Light.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/Lato-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akshaaatt/Onboarding-Android/e5c7187a9fdc99a03621a0df1bf00f875e34388c/app/src/main/assets/Lato-Regular.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/OpenSans-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akshaaatt/Onboarding-Android/e5c7187a9fdc99a03621a0df1bf00f875e34388c/app/src/main/assets/OpenSans-Light.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/OpenSans-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akshaaatt/Onboarding-Android/e5c7187a9fdc99a03621a0df1bf00f875e34388c/app/src/main/assets/OpenSans-Regular.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/nemoy_medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akshaaatt/Onboarding-Android/e5c7187a9fdc99a03621a0df1bf00f875e34388c/app/src/main/assets/nemoy_medium.ttf
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akshaaatt/Onboarding-Android/e5c7187a9fdc99a03621a0df1bf00f875e34388c/app/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/app/src/main/java/com/limurse/onboarding/IntroActivity.kt:
--------------------------------------------------------------------------------
1 | package com.limurse.onboarding
2 |
3 | import android.os.Build
4 | import android.os.Bundle
5 | import android.widget.Toast
6 | import androidx.fragment.app.Fragment
7 | import com.limurse.onboard.OnboardAdvanced
8 | import com.limurse.onboard.OnboardFragment
9 | import com.limurse.onboard.OnboardPageTransformerType
10 | import com.limurse.onboard.model.SliderPage
11 |
12 | class IntroActivity : OnboardAdvanced() {
13 | override fun onCreate(savedInstanceState: Bundle?) {
14 | super.onCreate(savedInstanceState)
15 |
16 | showSignInButton = true
17 | isWizardMode = true
18 | val permissions = when {
19 | Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> {
20 | listOf(
21 | android.Manifest.permission.ACCESS_COARSE_LOCATION,
22 | android.Manifest.permission.POST_NOTIFICATIONS
23 | )
24 | }
25 | else -> {
26 | listOf(android.Manifest.permission.ACCESS_COARSE_LOCATION)
27 | }
28 | }
29 |
30 | // Hide/Show the status Bar
31 | showStatusBar(true)
32 | setStatusBarColorRes(R.color.onboarder_bg_1)
33 |
34 | askForPermissions(
35 | permissions = permissions.toTypedArray(),
36 | slideNumber = 2,
37 | required = true
38 | )
39 |
40 | addSlide(OnboardFragment.newInstance(
41 | "Welcome!",
42 | "Ever wondered what was missing in your life?",
43 | resourceId = R.raw.teen,
44 | titleTypefaceFontRes = R.font.lato,
45 | descriptionTypefaceFontRes = R.font.lato,
46 | backgroundDrawable = R.drawable.back_slide2,
47 | isLottie = true
48 | ))
49 |
50 | addSlide(OnboardFragment.newInstance(
51 | SliderPage(
52 | "Tired of Searching?",
53 | "Congratulations, you are at the right place!",
54 | resourceId = R.raw.location,
55 | backgroundDrawable = R.drawable.back_slide1,
56 | titleTypeface = "OpenSans-Light.ttf",
57 | descriptionTypeface = "OpenSans-Light.ttf",
58 | isLottie = true
59 | )
60 | ))
61 |
62 | addSlide(OnboardFragment.newInstance(
63 | "Meet, Code and Discuss",
64 | "Connect with the community of fierce developers!",
65 | resourceId = R.raw.rocket,
66 | backgroundDrawable = R.drawable.back_slide3,
67 | titleTypefaceFontRes = R.font.opensans_regular,
68 | descriptionTypefaceFontRes = R.font.opensans_regular,
69 | isLottie = true
70 | ))
71 |
72 | addSlide(OnboardFragment.newInstance(
73 | "Explore and Learn",
74 | "Contribute to the community and build your reputation!",
75 | resourceId = R.raw.trophy,
76 | backgroundDrawable = R.drawable.back_slide4,
77 | isLottie = true
78 | ))
79 |
80 | addSlide(OnboardFragment.newInstance(
81 | "Are you ready?",
82 | "Join us, support us and become a part of us!",
83 | resourceId = R.drawable.metabrainz,
84 | ))
85 |
86 | setTransformer(OnboardPageTransformerType.Parallax())
87 | }
88 |
89 | override fun onSkipPressed(currentFragment: Fragment?) {
90 | super.onSkipPressed(currentFragment)
91 | Toast.makeText(applicationContext, "Skip pressed", Toast.LENGTH_SHORT).show()
92 | }
93 |
94 | override fun onSignInPressed(currentFragment: Fragment?) {
95 | super.onSignInPressed(currentFragment)
96 | Toast.makeText(applicationContext, "Sign In pressed", Toast.LENGTH_SHORT).show()
97 | }
98 |
99 | override fun onDonePressed(currentFragment: Fragment?) {
100 | super.onDonePressed(currentFragment)
101 | Toast.makeText(applicationContext, "Done pressed", Toast.LENGTH_SHORT).show()
102 | }
103 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/back_slide1.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/back_slide2.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/back_slide3.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/back_slide4.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/back_slide5.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/first.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akshaaatt/Onboarding-Android/e5c7187a9fdc99a03621a0df1bf00f875e34388c/app/src/main/res/drawable/first.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
6 |
10 |
13 |
16 |
19 |
22 |
25 |
28 |
31 |
34 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_slide1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akshaaatt/Onboarding-Android/e5c7187a9fdc99a03621a0df1bf00f875e34388c/app/src/main/res/drawable/ic_slide1.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_slide2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akshaaatt/Onboarding-Android/e5c7187a9fdc99a03621a0df1bf00f875e34388c/app/src/main/res/drawable/ic_slide2.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_slide3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akshaaatt/Onboarding-Android/e5c7187a9fdc99a03621a0df1bf00f875e34388c/app/src/main/res/drawable/ic_slide3.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_slide4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akshaaatt/Onboarding-Android/e5c7187a9fdc99a03621a0df1bf00f875e34388c/app/src/main/res/drawable/ic_slide4.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/metabrainz.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akshaaatt/Onboarding-Android/e5c7187a9fdc99a03621a0df1bf00f875e34388c/app/src/main/res/drawable/metabrainz.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/second.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akshaaatt/Onboarding-Android/e5c7187a9fdc99a03621a0df1bf00f875e34388c/app/src/main/res/drawable/second.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable/third.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akshaaatt/Onboarding-Android/e5c7187a9fdc99a03621a0df1bf00f875e34388c/app/src/main/res/drawable/third.jpg
--------------------------------------------------------------------------------
/app/src/main/res/font/lato.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/font/opensans_regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akshaaatt/Onboarding-Android/e5c7187a9fdc99a03621a0df1bf00f875e34388c/app/src/main/res/font/opensans_regular.ttf
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akshaaatt/Onboarding-Android/e5c7187a9fdc99a03621a0df1bf00f875e34388c/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akshaaatt/Onboarding-Android/e5c7187a9fdc99a03621a0df1bf00f875e34388c/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akshaaatt/Onboarding-Android/e5c7187a9fdc99a03621a0df1bf00f875e34388c/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akshaaatt/Onboarding-Android/e5c7187a9fdc99a03621a0df1bf00f875e34388c/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akshaaatt/Onboarding-Android/e5c7187a9fdc99a03621a0df1bf00f875e34388c/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akshaaatt/Onboarding-Android/e5c7187a9fdc99a03621a0df1bf00f875e34388c/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akshaaatt/Onboarding-Android/e5c7187a9fdc99a03621a0df1bf00f875e34388c/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akshaaatt/Onboarding-Android/e5c7187a9fdc99a03621a0df1bf00f875e34388c/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akshaaatt/Onboarding-Android/e5c7187a9fdc99a03621a0df1bf00f875e34388c/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akshaaatt/Onboarding-Android/e5c7187a9fdc99a03621a0df1bf00f875e34388c/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/raw/location.json:
--------------------------------------------------------------------------------
1 | {"v":"5.7.5","fr":60,"ip":0,"op":600,"w":1200,"h":1200,"nm":"with ai","ddd":0,"assets":[{"id":"image_0","w":72,"h":64,"u":"","p":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABACAMAAACOYMEYAAAAJHpUWHRDcmVhdG9yAAAImXNMyU9KVXBMK0ktUnBNS0tNLikGAEF6Bs5qehXFAAAACXBIWXMAAAABAAAAAQBPJcTWAAAA51BMVEVHcExgYP8PNWJfX/9fX/8TNWcQNWReX/4TO21fX/8WPXZhYPpgYP8YQXxfX/8YQn5eX/8LLVNdXfpNTc9fX/8KLVEYQn8LLlRfX//wrpkZQn8LMFYNMVsROGn/to75so3/t4z/t450bejcr64YQ38ZQn//t4u9kr5vaOT/t42egb1qZGlQVWNSVN+viXqCb29hYf//t41fX/8ZQ38KLVFKSsb/to4UPXISOWoPNWINMlsXQHkLL1VYWO5TU+H///5dXftPT9WDcaWsiclwZ7/w3sD/2Xj/vRtfYP9pZO/HlT3SsIe8jkoXe/oJAAAAMnRSTlMAEHcg4BBbYDryIKGAvkClgJ3r+cPw4NCytou26+DLfjDm/f3w0CCXzEjK9qVw7eVMYOBKiTwAAAJZSURBVFjDrdXXduIwEAZgYVzBtBN6DSE92TYulGBs2oYt7/88K1cwhj2W5P9KN3xnRh4NCLFG4EoFxB65omlahbkYsal5YSup0L3XglRYewpzT8+UtFgK2TCaJmfDUFUklz4+Ek6J/EuVptMk9CAQD/Fs6kJxqSmSliMOZrOEVCFmhN587kPH5h44gfyS+3MPOpbU7NJMD7dYLE6lZpdqdFBtufSgoDnyiwkd3YWCkgYUFxP2pWMokAYiw0PX9UCa9zmW9dXSfWmxaDFtsJoeQMsa0yIU9SBLjskRGiEkMjmol5HDBUxDZnPksDFGB7Wy6StqjNWRM3KEvu9wjA56950aI3M7NN9cp8fojEycr7reIlw+ZV4KTrk6Pj0OTS/fGqRLrA3ASzn3pOLT09h3zBHp3siDG6WKKQWUrRnmlvRGiuBHUb8DdAJlaI4RVUFeDpvnzo9H15q8miPaglzocGjn0cu4Y062ZjFPXZAnQbuM5+jlaQtABlXhLAeoY0oCKBI5OQUgSfHlZwCy1lS4nLtXlfCq19ZFyIFo3NPlxjBurCtV8WoutfPF8HKN8sY9bUF+Vg7+3a+7BJWyP8k4BlN/7MkZxad999b6hNr9tG2bqiB3qq1VBP3F0D5+R0TPzAnL+vy07V3s3qspIYkPp8Za4Wvf/N7vDeNksJT0nz+iPGy927iVRRTRcEv103l2LGuF45AW5O/++vmjxcvETZH47ydB+QXlKf7J8sX4HiGYxf9T6WfxEqUqFI/j8ro8oSSE2CgeqD791RmtogyCqQwK8geL7Ib+Abc/0YffNI5ZAAAAAElFTkSuQmCC","e":1},{"id":"image_1","w":19,"h":32,"u":"","p":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAAgBAMAAAACkF78AAAAJHpUWHRDcmVhdG9yAAAImXNMyU9KVXBMK0ktUnBNS0tNLikGAEF6Bs5qehXFAAAACXBIWXMAAAABAAAAAQBPJcTWAAAAKlBMVEVHcExfX/9gYP9fX/9gXv9eX/9eXv9fYP9gX/9gYP9fX/9fYP9fX/9fX/80LGIqAAAADXRSTlMAmxDwLNBwgFxAwOCwvPh5hwAAAItJREFUGNNjYICCBgY4uABnMSGYnFiZ7AgmI4LJimD6BsCZvQvgzLUCMBbL3QK4AXcnwJjKdxVgTNmrCKUXYUyuu1dgzNy7G2DytnCzWO9ehhkge/c6lMVx964RlOl8924C1Ie2d2EWqN6Fm3oWLs94F25r7t27AnBNMEGeu5dhITf3dhLMUWUOMBYAKg0vnb5Rc34AAAAASUVORK5CYII=","e":1},{"id":"image_2","w":90,"h":164,"u":"","p":"data:image/png;base64,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","e":1},{"id":"image_3","w":28,"h":24,"u":"","p":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAYCAMAAADeQm2wAAAAJHpUWHRDcmVhdG9yAAAImXNMyU9KVXBMK0ktUnBNS0tNLikGAEF6Bs5qehXFAAAACXBIWXMAAAABAAAAAQBPJcTWAAAAeFBMVEVHcEz/skb/qkL/tEb/yVD/1XD/pkD/qUL/t0X/tkr/v0v/uEj/pD//rEz/nj3/3H7/02v/q0P/02P/p0H/tEb/23v/1Gv/23r/3oT/s0b/r0T/t0f/pkD/4pL/5Jv/vEr/q0L/4Iv/2G//wU3/x1f/0mX/oT7/nDwii1JQAAAAF3RSTlMAYPBQwvlwhRA68JjQH8CtgbDO4ODg1JHXFOcAAAD5SURBVCjPddLbcoMgEAZgPIx4TswkVcEUhEXf/w27WGW10/y33zB7grEjeVSlafr1et3uDbsmr0proX+/v31uF0tKZa2b5/euZ4ukUgqGIWhBVkiJagbSO9V7Ikroe1IqyscR0fUnfQSMBeqIvZIGTITwuj3ddU4PrPSmYExQE7DtKq/OBB0gpVE6fCs9mt54BUujFFprYZ1Xh105a20SsJ5QwWFAKrBK2ZL2Ok2oACB9z8qHB2wnr0LsEyGX+WHNsmyqdVBaO1/+akRz1Ouhdeb1eTpXs66/GnOGGPPLnddNY45NZF10/TzcY53l7L+0a5sV7EMa9jk/u1UoZOck4ggAAAAASUVORK5CYII=","e":1},{"id":"image_4","w":28,"h":24,"u":"","p":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAYCAMAAADeQm2wAAAAJHpUWHRDcmVhdG9yAAAImXNMyU9KVXBMK0ktUnBNS0tNLikGAEF6Bs5qehXFAAAACXBIWXMAAAABAAAAAQBPJcTWAAAAclBMVEVHcEz/skX/0GP/qkL/t0L/yVH/pkD/tEb/p0D/o0D/v0r/oz//qkr/02f/u1H/ukj/3oP/tEb/1nD/233/2Xv/uUj/rEP/3oT/23v/tEb/oz//v0z/4pL/5Jv/sET/4Iv/1Wn/2XP/qEH/nDz/xVX/zF4qNQEnAAAAFXRSTlMAYIHwEMJwSYe58NAf0DSbtOCg4ODV9iu5AAAA80lEQVQoz3XS23aDIBAFUIyCoCYmbfGGVVD4/1/MDKmAWc158GWvEQ5AyJEiayml15/v+6Uh5xRtpZQb5vkXcz9ZCaTcus5/mlompVS274PekrkRUJo+6iWu9xhB7TBE/QrIR4h0Q6LXgPmCqlINWC6LV22CrvTAtvNqjQmqAwrBUZ0O2lsaqwiYlVqjGlSrYpVy67pFaVQNhTQcVhmw3kAtmLNSOSBVxcFpA3UgWBcPMvmrmLy+9uy1Kg5rpuld44p8f9cs9qg9otYM9ZFcV7NDEHNOWLfAN73nF+YcNsFEdn48HLFmBfkvYhfsRj6kIZ/zBBbtJcBsisT1AAAAAElFTkSuQmCC","e":1},{"id":"image_5","w":166,"h":188,"u":"","p":"data:image/png;base64,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","e":1},{"id":"image_6","w":32,"h":27,"u":"","p":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAbCAMAAAAqGX2oAAAAJHpUWHRDcmVhdG9yAAAImXNMyU9KVXBMK0ktUnBNS0tNLikGAEF6Bs5qehXFAAAACXBIWXMAAAABAAAAAQBPJcTWAAAAQlBMVEVHcEyv4v+u4/+v4/+u4v+u4v+u4v+v4f+u4v+v4v+t4v+u4/+u4v+f3/+u4v+15f/B5/vy+PfP5+3f7u/G4+yt2+0PNOwTAAAADnRSTlMAm9AQ4PBgILw4gHBQEPe5R8AAAADjSURBVCjPhZPbAoQgCES7qGm1qGn//6uroKbVuj6VZ4CBaBhuR4zL0D0jQF/CALoSAXSk6iXoSNZAvM6S/cFVuNaHPbKEiZbPHK9rydjwKULdSLYbj8jkLPGh6lelBoxzJPEu+Lz4Fu8o2liXLRSTamqiswWW8CIRGozOLuMbzWqXqTiy7NKcycGG3ry7WK4DHFtYqLq3x2XPWF/PYKXxYZz2mERHgbxPIMRpLEA9svmawUemJBhOSXj7tQWvkmj94MVrGNEJ8MKLVzDRwfS6k6qs2/pjH2fyKjtbLzj/89886RfGqxgOIr+HEQAAAABJRU5ErkJggg==","e":1},{"id":"comp_0","layers":[{"ddd":0,"ind":1,"ty":0,"nm":"rocket with man","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[600,600,0],"ix":2,"l":2},"a":{"a":0,"k":[600,600,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":113.5,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":166,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":14,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":41,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"w":1200,"h":1200,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[541,622,0],"ix":2,"l":2},"a":{"a":0,"k":[-166,-163,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[734,734],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.630859375,0.047882080078,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-166,-163],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_1","layers":[{"ddd":0,"ind":1,"ty":2,"nm":"Hand with bag","parent":6,"refId":"image_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[-22.053]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":150.506,"s":[-10.053]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":301.014,"s":[-26.053]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":449.307,"s":[-12.053]},{"t":597.599609375,"s":[-26.053]}],"ix":10},"p":{"a":0,"k":[21.356,4.972,0],"ix":2,"l":2},"a":{"a":0,"k":[67.667,2.446,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":2,"nm":"tai","parent":6,"refId":"image_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[-3]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":87.322,"s":[21]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":177.656,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":271,"s":[10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":361.332,"s":[20]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":451.668,"s":[5]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":542,"s":[20]},{"t":598,"s":[0]}],"ix":10},"p":{"a":0,"k":[35.55,8.572,0],"ix":2,"l":2},"a":{"a":0,"k":[16.502,-0.037,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":2,"nm":"Man","parent":6,"refId":"image_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[53.91,55.695,0],"ix":2,"l":2},"a":{"a":0,"k":[44.577,81.652,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":2,"nm":"Layer 8","parent":6,"refId":"image_3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[42.62,181.34,0],"ix":2,"l":2},"a":{"a":0,"k":[21.74,1.935,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":0,"s":[0,0,100]},{"t":74,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":2,"nm":"Fire","parent":6,"refId":"image_4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[8.049,151.143,0],"ix":2,"l":2},"a":{"a":0,"k":[21.24,2.56,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":0,"s":[0,0,100]},{"t":74,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":2,"nm":"Rocket","refId":"image_5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[584.076,665.4,0],"to":[2.938,-2.5,0],"ti":[0.729,-1.667,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":149.502,"s":[601.701,650.4,0],"to":[-0.729,1.667,0],"ti":[-4.167,4.167,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":299.002,"s":[579.701,675.4,0],"to":[4.167,-4.167,0],"ti":[-4,4.417,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":448.502,"s":[626.701,625.4,0],"to":[4,-4.417,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":598,"s":[603.701,648.9,0],"to":[0,0,0],"ti":[-3.833,3.917,0]},{"t":952,"s":[626.701,625.4,0]}],"ix":2,"l":2},"a":{"a":0,"k":[82.714,93.613,0],"ix":1,"l":2},"s":{"a":0,"k":[364,364,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":2,"nm":"Paper2","refId":"image_6","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":316,"s":[74]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":390,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":450,"s":[74]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":524,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":630,"s":[74]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":704,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":758,"s":[74]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":832,"s":[0]},{"t":892,"s":[74]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":432,"s":[233.153,519.841,0],"to":[-129.108,-301.167,0],"ti":[49.199,-84.125,0]},{"t":914,"s":[-209.687,998.591,0]}],"ix":2,"l":2},"a":{"a":0,"k":[15.878,13.159,0],"ix":1,"l":2},"s":{"a":0,"k":[364,364,100],"ix":6,"l":2}},"ao":0,"ip":432,"op":916,"st":316,"bm":0},{"ddd":0,"ind":10,"ty":2,"nm":"Paper1","refId":"image_6","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":38,"s":[74]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":112,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":172,"s":[74]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":246,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":352,"s":[74]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":426,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":480,"s":[74]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":554,"s":[0]},{"t":614,"s":[74]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":38,"s":[241.153,549.841,0],"to":[-92.14,-309.208,0],"ti":[75.14,-74.792,0]},{"t":636,"s":[-209.687,998.591,0]}],"ix":2,"l":2},"a":{"a":0,"k":[15.878,13.159,0],"ix":1,"l":2},"s":{"a":0,"k":[364,364,100],"ix":6,"l":2}},"ao":0,"ip":38,"op":638,"st":38,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"rocket man 2","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[600,600,0],"ix":2,"l":2},"a":{"a":0,"k":[600,600,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":1200,"h":1200,"ip":0,"op":600,"st":0,"bm":0}],"markers":[]}
--------------------------------------------------------------------------------
/app/src/main/res/raw/music.json:
--------------------------------------------------------------------------------
1 | {"v":"5.5.7","meta":{"g":"LottieFiles AE 0.1.20","a":"","k":"","d":"","tc":"#E21010"},"fr":30,"ip":0,"op":360,"w":1080,"h":1080,"nm":"music loading_render","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":2,"ty":3,"nm":"Null 2","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[556,846.812,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":80,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":3,"nm":"Null 1","parent":2,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.738,"y":1},"o":{"x":0.246,"y":0},"t":0,"s":[-8,-388.812,0],"to":[0,8.532,0],"ti":[0,0,0]},{"i":{"x":0.708,"y":1},"o":{"x":0.326,"y":0},"t":19,"s":[-8,-337.62,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.738,"y":1},"o":{"x":0.333,"y":0},"t":39,"s":[-8,-388.812,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.708,"y":1},"o":{"x":0.326,"y":0},"t":59,"s":[-8,-337.62,0],"to":[0,0,0],"ti":[0,8.532,0]},{"t":78,"s":[-8,-388.812,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[135,135,100],"ix":6}},"ao":0,"ip":0,"op":80,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"mata","parent":7,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.1,"y":0},"t":0,"s":[470,432.821,0],"to":[-3.167,-4.5,0],"ti":[6.167,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0,"y":0},"t":19,"s":[451,405.821,0],"to":[-6.167,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":39,"s":[433,432.821,0],"to":[0,0,0],"ti":[-6.167,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0,"y":0},"t":59,"s":[451,405.821,0],"to":[6.167,0,0],"ti":[-3.167,-4.5,0]},{"t":78,"s":[470,432.821,0]}],"ix":2},"a":{"a":0,"k":[448,396,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0,"y":0},"t":8,"s":[{"i":[[0,-15.74],[15.74,0],[0,15.74],[-15.74,0]],"o":[[0,15.74],[-15.74,0],[0,-15.74],[15.74,0]],"v":[[28.5,0],[0,28.5],[-28.5,0],[0,-28.5]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0,"y":0},"t":11,"s":[{"i":[[4.243,-7.669],[15.74,0],[6.704,10.678],[-15.74,0]],"o":[[-6.046,10.928],[-15.74,0],[-5.63,-8.968],[15.74,0]],"v":[[28.5,0],[-0.5,-3.25],[-28.5,0],[0.25,-19.5]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":14,"s":[{"i":[[0,-15.74],[15.74,0],[0,15.74],[-15.74,0]],"o":[[0,15.74],[-15.74,0],[0,-15.74],[15.74,0]],"v":[[28.5,0],[0,28.5],[-28.5,0],[0,-28.5]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0,"y":0},"t":49,"s":[{"i":[[0,-15.74],[15.74,0],[0,15.74],[-15.74,0]],"o":[[0,15.74],[-15.74,0],[0,-15.74],[15.74,0]],"v":[[28.5,0],[0,28.5],[-28.5,0],[0,-28.5]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0,"y":0},"t":52,"s":[{"i":[[4.243,-7.669],[15.74,0],[6.704,10.678],[-15.74,0]],"o":[[-6.046,10.928],[-15.74,0],[-5.63,-8.968],[15.74,0]],"v":[[28.5,0],[-0.5,-3.25],[-28.5,0],[0.25,-19.5]],"c":true}]},{"t":55,"s":[{"i":[[0,-15.74],[15.74,0],[0,15.74],[-15.74,0]],"o":[[0,15.74],[-15.74,0],[0,-15.74],[15.74,0]],"v":[[28.5,0],[0,28.5],[-28.5,0],[0,-28.5]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[381.5,396.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0,"y":0},"t":8,"s":[{"i":[[0,-15.74],[15.74,0],[0,15.74],[-15.74,0]],"o":[[0,15.74],[-15.74,0],[0,-15.74],[15.74,0]],"v":[[-90.5,0],[-119,28.5],[-147.5,0],[-119,-28.5]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0,"y":0},"t":11,"s":[{"i":[[4.243,-7.669],[15.74,0],[6.704,10.678],[-15.74,0]],"o":[[-6.046,10.928],[-15.74,0],[-5.63,-8.968],[15.74,0]],"v":[[-90.5,0],[-119.5,-3.25],[-147.5,0],[-118.75,-19.5]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":14,"s":[{"i":[[0,-15.74],[15.74,0],[0,15.74],[-15.74,0]],"o":[[0,15.74],[-15.74,0],[0,-15.74],[15.74,0]],"v":[[-90.5,0],[-119,28.5],[-147.5,0],[-119,-28.5]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0,"y":0},"t":49,"s":[{"i":[[0,-15.74],[15.74,0],[0,15.74],[-15.74,0]],"o":[[0,15.74],[-15.74,0],[0,-15.74],[15.74,0]],"v":[[-90.5,0],[-119,28.5],[-147.5,0],[-119,-28.5]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0,"y":0},"t":52,"s":[{"i":[[4.243,-7.669],[15.74,0],[6.704,10.678],[-15.74,0]],"o":[[-6.046,10.928],[-15.74,0],[-5.63,-8.968],[15.74,0]],"v":[[-90.5,0],[-119.5,-3.25],[-147.5,0],[-118.75,-19.5]],"c":true}]},{"t":55,"s":[{"i":[[0,-15.74],[15.74,0],[0,15.74],[-15.74,0]],"o":[[0,15.74],[-15.74,0],[0,-15.74],[15.74,0]],"v":[[-90.5,0],[-119,28.5],[-147.5,0],[-119,-28.5]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[632.5,396.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":80,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Shape Layer 2","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[545.809,641.328,0],"to":[-19,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":39,"s":[431.809,641.328,0],"to":[0,0,0],"ti":[-19,0,0]},{"t":78,"s":[545.809,641.328,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[143.277,160.158,100],"ix":6}},"ao":0,"shapes":[{"d":1,"ty":"el","s":{"a":0,"k":[431,431],"ix":2},"p":{"a":0,"k":[146,-36],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":80,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"wajah 3","parent":3,"tt":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[27.5,24,0],"to":[-4.667,-13,0],"ti":[9.083,1.333,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":19,"s":[-0.5,-54,0],"to":[-9.083,-1.333,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":39,"s":[-27,16,0],"to":[0,0,0],"ti":[-9.083,-1.333,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":59,"s":[-0.5,-54,0],"to":[9.083,1.333,0],"ti":[-4.667,-13,0]},{"t":78,"s":[27.5,24,0]}],"ix":2},"a":{"a":0,"k":[451,392,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[0,0],[-38.239,0.47],[-17.5,13.834],[5.611,-29.185],[8.167,-9.953],[19.982,7.092],[5.25,-4],[19,-8.5],[17.535,4.749],[2,55.5],[0,0],[-37.104,21.162]],"o":[[0,0],[19.593,-0.241],[-2.981,39.389],[-7.197,37.433],[-13.623,16.603],[-19.25,-6.832],[-5.75,-5.5],[-19,8.5],[-18.833,-5.101],[-2,-55.5],[0,0],[43.833,-25]],"v":[[489.13,309.111],[546.13,378.611],[591.666,363.426],[582.333,443.852],[553.852,499.435],[508.703,512.76],[472.37,518.926],[432.203,515.093],[359.5,513.601],[309.5,416.5],[314,364.75],[431.797,380.944]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":19,"s":[{"i":[[0,0],[-33.088,-19.174],[-17.5,13.834],[3,-38],[21,-4.5],[27.167,10],[5.25,-4],[19,-8.5],[17.535,4.749],[2,55.5],[0,0],[-37.104,21.162]],"o":[[0,0],[32.5,18.833],[5.41,39],[-3,38],[-21,4.5],[-19.169,-7.056],[-5.75,-5.5],[-19,8.5],[-18.833,-5.101],[-2,-55.5],[0,0],[43.833,-25]],"v":[[446.167,275.333],[503.167,344.833],[585,328.166],[589,425.333],[554.5,519.305],[498.5,493],[448.667,497.166],[399,494.333],[344.5,518.601],[309.5,416.5],[314,328.75],[388.834,347.166]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":39,"s":[{"i":[[0,0],[-33.088,-19.174],[-17.5,13.834],[3,-38],[21,-4.5],[27.167,10],[5.25,-4],[19,-8.5],[13.436,12.227],[6.278,33.574],[0,0],[-33.797,10.611]],"o":[[0,0],[32.5,18.833],[5.41,39],[-3,38],[-21,4.5],[-19.169,-7.056],[-5.75,-5.5],[-19,8.5],[-10.389,-9.453],[-5.475,-29.276],[0,0],[48.144,-15.116]],"v":[[415.796,315.778],[472.796,385.278],[585,364.166],[589,425.333],[542,509.805],[469.444,513.5],[433.111,519.666],[392.944,515.833],[353.574,500.268],[321.352,435.76],[317.703,364.75],[358.463,387.611]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":59,"s":[{"i":[[0,0],[-33.088,-19.174],[-17.5,13.834],[3,-38],[21,-4.5],[27.167,10],[5.25,-4],[19,-8.5],[17.535,4.749],[2,55.5],[0,0],[-37.104,21.162]],"o":[[0,0],[32.5,18.833],[5.41,39],[-3,38],[-21,4.5],[-19.169,-7.056],[-5.75,-5.5],[-19,8.5],[-18.833,-5.101],[-2,-55.5],[0,0],[43.833,-25]],"v":[[446.167,275.333],[503.167,344.833],[585,328.166],[589,425.333],[554.5,519.305],[498.5,493],[448.667,497.166],[399,494.333],[344.5,518.601],[309.5,416.5],[314,328.75],[388.834,347.166]],"c":true}]},{"t":78,"s":[{"i":[[0,0],[-38.239,0.47],[-17.5,13.834],[5.611,-29.185],[8.167,-9.953],[19.982,7.092],[5.25,-4],[19,-8.5],[17.535,4.749],[2,55.5],[0,0],[-37.104,21.162]],"o":[[0,0],[19.593,-0.241],[-2.981,39.389],[-7.197,37.433],[-13.623,16.603],[-19.25,-6.832],[-5.75,-5.5],[-19,8.5],[-18.833,-5.101],[-2,-55.5],[0,0],[43.833,-25]],"v":[[489.13,309.111],[546.13,378.611],[591.666,363.426],[582.333,443.852],[553.852,499.435],[508.703,512.76],[472.37,518.926],[432.203,515.093],[359.5,513.601],[309.5,416.5],[314,364.75],[431.797,380.944]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.722352981567,0.721219837666,0.721219837666,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"gr","it":[{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[449.75,382.069],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[],"o":[],"v":[],"c":false},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false}],"ip":0,"op":80,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"wajah ","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[27.5,24,0],"to":[-4.667,-13,0],"ti":[9.083,1.333,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":19,"s":[-0.5,-54,0],"to":[-9.083,-1.333,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":39,"s":[-27,16,0],"to":[0,0,0],"ti":[-9.083,-1.333,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":59,"s":[-0.5,-54,0],"to":[9.083,1.333,0],"ti":[-4.667,-13,0]},{"t":78,"s":[27.5,24,0]}],"ix":2},"a":{"a":0,"k":[451,392,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[0,0],[-38.239,0.47],[-17.5,13.834],[5.611,-29.185],[8.167,-9.953],[19.982,7.092],[5.25,-4],[19,-8.5],[17.535,4.749],[2,55.5],[0,0],[-37.104,21.162]],"o":[[0,0],[19.593,-0.241],[-2.981,39.389],[-7.197,37.433],[-13.623,16.603],[-19.25,-6.832],[-5.75,-5.5],[-19,8.5],[-18.833,-5.101],[-2,-55.5],[0,0],[43.833,-25]],"v":[[489.13,309.111],[546.13,378.611],[591.666,363.426],[582.333,443.852],[553.852,499.435],[508.703,512.76],[472.37,518.926],[432.203,515.093],[359.5,513.601],[309.5,416.5],[314,364.75],[431.797,380.944]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":19,"s":[{"i":[[0,0],[-33.088,-19.174],[-17.5,13.834],[3,-38],[21,-4.5],[27.167,10],[5.25,-4],[19,-8.5],[17.535,4.749],[2,55.5],[0,0],[-37.104,21.162]],"o":[[0,0],[32.5,18.833],[5.41,39],[-3,38],[-21,4.5],[-19.169,-7.056],[-5.75,-5.5],[-19,8.5],[-18.833,-5.101],[-2,-55.5],[0,0],[43.833,-25]],"v":[[446.167,275.333],[503.167,344.833],[585,328.166],[589,425.333],[554.5,519.305],[498.5,493],[448.667,497.166],[399,494.333],[344.5,518.601],[309.5,416.5],[314,328.75],[388.834,347.166]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":39,"s":[{"i":[[0,0],[-33.088,-19.174],[-17.5,13.834],[3,-38],[21,-4.5],[27.167,10],[5.25,-4],[19,-8.5],[13.436,12.227],[6.278,33.574],[0,0],[-33.797,10.611]],"o":[[0,0],[32.5,18.833],[5.41,39],[-3,38],[-21,4.5],[-19.169,-7.056],[-5.75,-5.5],[-19,8.5],[-10.389,-9.453],[-5.475,-29.276],[0,0],[48.144,-15.116]],"v":[[415.796,315.778],[472.796,385.278],[585,364.166],[589,425.333],[542,509.805],[469.444,513.5],[433.111,519.666],[392.944,515.833],[353.574,500.268],[321.352,435.76],[317.703,364.75],[358.463,387.611]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":59,"s":[{"i":[[0,0],[-33.088,-19.174],[-17.5,13.834],[3,-38],[21,-4.5],[27.167,10],[5.25,-4],[19,-8.5],[17.535,4.749],[2,55.5],[0,0],[-37.104,21.162]],"o":[[0,0],[32.5,18.833],[5.41,39],[-3,38],[-21,4.5],[-19.169,-7.056],[-5.75,-5.5],[-19,8.5],[-18.833,-5.101],[-2,-55.5],[0,0],[43.833,-25]],"v":[[446.167,275.333],[503.167,344.833],[585,328.166],[589,425.333],[554.5,519.305],[498.5,493],[448.667,497.166],[399,494.333],[344.5,518.601],[309.5,416.5],[314,328.75],[388.834,347.166]],"c":true}]},{"t":78,"s":[{"i":[[0,0],[-38.239,0.47],[-17.5,13.834],[5.611,-29.185],[8.167,-9.953],[19.982,7.092],[5.25,-4],[19,-8.5],[17.535,4.749],[2,55.5],[0,0],[-37.104,21.162]],"o":[[0,0],[19.593,-0.241],[-2.981,39.389],[-7.197,37.433],[-13.623,16.603],[-19.25,-6.832],[-5.75,-5.5],[-19,8.5],[-18.833,-5.101],[-2,-55.5],[0,0],[43.833,-25]],"v":[[489.13,309.111],[546.13,378.611],[591.666,363.426],[582.333,443.852],[553.852,499.435],[508.703,512.76],[472.37,518.926],[432.203,515.093],[359.5,513.601],[309.5,416.5],[314,364.75],[431.797,380.944]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"gr","it":[{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[449.75,382.069],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[],"o":[],"v":[],"c":false},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false}],"ip":0,"op":80,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"mulut 2","parent":7,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[452.721,565.192,0],"ix":2},"a":{"a":0,"k":[449,555,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[-36.157,-0.884],[-1.903,-17.367],[11.228,-0.294],[7.802,9.42],[12.94,4.121],[0.016,7.806]],"o":[[13.125,0.321],[1.522,12.363],[-11.228,0.294],[-6.185,8.757],[-12.94,-4.121],[-0.021,-9.776]],"v":[[0.629,-36.804],[47.062,-17.597],[26.129,3.523],[-1.465,-7],[-31.151,2.566],[-48.563,-16.505]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":19,"s":[{"i":[[-47.5,-1.5],[-2.5,-29.5],[14.75,-0.5],[10.25,16],[17,7],[0.022,13.26]],"o":[[17.243,0.545],[2,21],[-14.75,0.5],[-8.125,14.875],[-17,-7],[-0.027,-16.605]],"v":[[0.826,-36.188],[61.826,-3.563],[34.326,32.313],[-1.924,14.438],[-40.924,30.688],[-63.799,-1.708]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":39,"s":[{"i":[[-36.157,-0.884],[-1.903,-17.367],[11.228,-0.294],[7.802,9.42],[12.94,4.121],[0.016,7.806]],"o":[[13.125,0.321],[1.522,12.363],[-11.228,0.294],[-6.185,8.757],[-12.94,-4.121],[-0.021,-9.776]],"v":[[0.629,-36.804],[47.062,-17.597],[26.129,3.523],[-1.465,-7],[-31.151,2.566],[-48.563,-16.505]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":59,"s":[{"i":[[-47.5,-1.5],[-2.5,-29.5],[14.75,-0.5],[10.25,16],[17,7],[0.022,13.26]],"o":[[17.243,0.545],[2,21],[-14.75,0.5],[-8.125,14.875],[-17,-7],[-0.027,-16.605]],"v":[[0.826,-36.188],[61.826,-3.563],[34.326,32.313],[-1.924,14.438],[-40.924,30.688],[-63.799,-1.708]],"c":true}]},{"t":78,"s":[{"i":[[-36.157,-0.884],[-1.903,-17.367],[11.228,-0.294],[7.802,9.42],[12.94,4.121],[0.016,7.806]],"o":[[13.125,0.321],[1.522,12.363],[-11.228,0.294],[-6.185,8.757],[-12.94,-4.121],[-0.021,-9.776]],"v":[[0.629,-36.804],[47.062,-17.597],[26.129,3.523],[-1.465,-7],[-31.151,2.566],[-48.563,-16.505]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[450.174,565.313],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":80,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"head set","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.5,12.287,0],"ix":2},"a":{"a":0,"k":[445,384,0],"ix":1},"s":{"a":0,"k":[100,101.856,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[24.906,23.177],[0,8.782],[123.712,0],[0,-127.197],[-0.399,-5.621],[5.589,-13.508],[0,0],[-22,-13.5],[-21,-2],[0,0],[13.702,-2.275],[0,1.187],[-104.577,0],[0,-107.523],[0.033,-1.506],[0.704,-27.325],[15.092,-36.659],[-25.5,16],[0,0],[0,0]],"o":[[0.931,-8.526],[0,-127.197],[-123.712,0],[0,5.727],[-15.385,11.476],[0.5,55.5],[0,0],[22,13.5],[39.769,-113.747],[0,0],[-0.021,-1.182],[0,-107.523],[104.576,0],[0,1.514],[1.757,71.297],[-0.704,27.325],[25,-3.5],[25.5,-16],[0,0],[0,0]],"v":[[224.578,24.885],[226.129,-1.083],[2.191,-231.395],[-221.778,-1.083],[-221.152,15.941],[-257.254,51.396],[-257.25,174.396],[-223.748,210.896],[-162.497,231.395],[-161.747,-1.104],[-186.055,1.285],[-186.089,-1.083],[3.259,-195.771],[192.609,-1.083],[192.552,3.445],[195.754,119.413],[171.809,231.395],[223.024,205.896],[257.254,158.896],[257.254,64.396]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":19,"s":[{"i":[[12.694,-1.034],[1.395,7.97],[123.712,0],[2.532,-67.946],[-0.399,-5.179],[5.589,-12.445],[0,0],[-22,-12.438],[-22.453,15.127],[0,0],[14.438,4.712],[0,1.094],[-104.577,0],[-3.855,-95.927],[0.033,-1.388],[0,0],[-10.093,-21.962],[-16.122,15.35],[-8.13,17.2],[0,0]],"o":[[0.931,-7.855],[-11.375,-65.001],[-123.712,0],[-0.196,5.273],[-12.687,5.026],[-5.474,13.085],[0,0],[22,12.438],[17.547,-12.508],[0,0],[-0.021,-1.089],[0,-99.066],[104.576,0],[0.056,1.394],[-10.835,9.267],[0,0],[12.87,20.945],[12.767,-5.013],[3.722,-10.435],[0,0]],"v":[[229.022,21.82],[226.129,4.439],[3.191,-173.396],[-221.778,4.439],[-223.374,17.942],[-253.55,41.154],[-257.25,116.045],[-228.933,149.674],[-181.756,160.562],[-167.673,53.872],[-184.944,6.62],[-184.978,4.438],[2.259,-173.955],[192.609,4.439],[192.552,8.611],[173.532,54.296],[177.735,159.107],[227.468,152.34],[257.254,117.763],[253.55,42.95]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":39,"s":[{"i":[[24.906,23.177],[0,8.782],[123.712,0],[0,-127.197],[-0.399,-5.621],[5.589,-13.508],[0,0],[-22,-13.5],[-21,-2],[0,0],[-3.34,79.275],[0,1.187],[-104.577,0],[0,-107.523],[0.033,-1.506],[0,0],[-33.056,-103.565],[-25.5,16],[0,0],[0,0]],"o":[[0.931,-8.526],[0,-127.197],[-123.712,0],[0,5.727],[-15.385,11.476],[0.5,55.5],[0,0],[22,13.5],[-29.861,-62.112],[0,0],[-0.021,-1.182],[0,-107.523],[104.576,0],[0,1.514],[-20.5,-7.502],[0,0],[25,-3.5],[25.5,-16],[0,0],[0,0]],"v":[[224.578,24.885],[226.129,-1.083],[2.191,-231.395],[-221.778,-1.083],[-221.152,15.941],[-257.254,51.396],[-257.25,174.396],[-223.748,210.896],[-167.682,231.395],[-189.154,116.709],[-186.055,1.285],[-186.089,-1.083],[3.259,-195.771],[192.609,-1.083],[192.552,3.445],[155.754,0.146],[156.254,231.395],[223.024,205.896],[257.254,158.896],[257.254,64.396]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":59,"s":[{"i":[[12.694,-1.034],[1.395,7.97],[123.712,0],[2.532,-67.946],[-0.399,-5.179],[5.589,-12.445],[0,0],[-22,-12.438],[-22.453,15.127],[0,0],[14.438,4.712],[0,1.094],[-104.577,0],[-3.855,-95.927],[0.033,-1.388],[0,0],[-10.093,-21.962],[-16.122,15.35],[-8.13,17.2],[0,0]],"o":[[0.931,-7.855],[-11.375,-65.001],[-123.712,0],[-0.196,5.273],[-12.687,5.026],[-5.474,13.085],[0,0],[22,12.438],[17.547,-12.508],[0,0],[-0.021,-1.089],[0,-99.066],[104.576,0],[0.056,1.394],[-10.835,9.267],[0,0],[12.87,20.945],[12.767,-5.013],[3.722,-10.435],[0,0]],"v":[[229.022,21.82],[226.129,4.439],[3.191,-173.396],[-221.778,4.439],[-223.374,17.942],[-253.55,41.154],[-257.25,116.045],[-228.933,149.674],[-181.756,160.562],[-167.673,53.872],[-184.944,6.62],[-184.978,4.439],[2.259,-173.955],[192.609,4.439],[192.552,8.611],[173.532,54.296],[177.735,159.108],[227.468,152.34],[257.254,117.763],[253.55,42.95]],"c":true}]},{"t":78,"s":[{"i":[[24.906,23.177],[0,8.782],[123.712,0],[0,-127.197],[-0.399,-5.621],[5.589,-13.508],[0,0],[-22,-13.5],[-21,-2],[0,0],[13.702,-2.275],[0,1.187],[-104.577,0],[0,-107.523],[0.033,-1.506],[0.704,-27.325],[15.092,-36.659],[-25.5,16],[0,0],[0,0]],"o":[[0.931,-8.526],[0,-127.197],[-123.712,0],[0,5.727],[-15.385,11.476],[0.5,55.5],[0,0],[22,13.5],[39.769,-113.747],[0,0],[-0.021,-1.182],[0,-107.523],[104.576,0],[0,1.514],[1.757,71.297],[-0.704,27.325],[25,-3.5],[25.5,-16],[0,0],[0,0]],"v":[[224.578,24.885],[226.129,-1.083],[2.191,-231.395],[-221.778,-1.083],[-221.152,15.941],[-257.254,51.396],[-257.25,174.396],[-223.748,210.896],[-162.497,231.395],[-161.747,-1.104],[-186.055,1.285],[-186.089,-1.083],[3.259,-195.771],[192.609,-1.083],[192.552,3.445],[195.754,119.413],[171.809,231.395],[223.024,205.896],[257.254,158.896],[257.254,64.396]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[446.746,292.105],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":80,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"rambut ","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.5,0,0],"ix":2},"a":{"a":0,"k":[445,384,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-54,-54.268],[-3,-13.5],[-5,-33.5],[57.241,-4.581],[45,-2.5],[25.145,23.937],[-13.5,148.5],[-57.972,54.503]],"o":[[0,0],[49.143,49.388],[3,13.5],[5,33.5],[-24.241,4.308],[-38.969,2.165],[-19,9],[11.711,-128.818],[54,-50.768]],"v":[[2.808,-262.699],[136,-208.699],[192.5,-89.699],[206.5,70.301],[82,228.801],[9.25,260.801],[-72.895,231.614],[-195,19.301],[-132.5,-212.199]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.2,0.246999987434,0.310000011968,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[447,385.699],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":80,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"Shape Layer 3","sr":1,"ks":{"o":{"a":0,"k":87,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[561,998,0],"ix":2},"a":{"a":0,"k":[7,386,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[44.011,0],[0,-31],[-177,0],[0.949,28.002]],"o":[[-55,0],[0,31],[67.03,0],[-2,-59]],"v":[[-64,334],[-195,378],[91,439],[215,378]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":19,"s":[{"i":[[44.011,0],[0,-31],[-51,0],[1,28]],"o":[[-55,0],[0,31],[55,0],[-1,-28]],"v":[[17,347],[-195,378],[18,420],[215,378]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":39,"s":[{"i":[[44.011,0],[-2,-64],[-51,0],[1,28]],"o":[[-55,0],[0.968,30.985],[134,0],[-1,-28]],"v":[[95.5,334.5],[-195,378],[-80,443],[215,378]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":59,"s":[{"i":[[44.011,0],[0,-31],[-51,0],[1,28]],"o":[[-55,0],[0,31],[55,0],[-1,-28]],"v":[[17,347],[-195,378],[18,420],[215,378]],"c":true}]},{"t":78,"s":[{"i":[[44.011,0],[0,-31],[-177,0],[0.949,28.002]],"o":[[-55,0],[0,31],[67.03,0],[-2,-59]],"v":[[-64,334],[-195,378],[91,439],[215,378]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":360,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"music loading","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[536,520,0],"ix":2},"a":{"a":0,"k":[540,540,0],"ix":1},"s":{"a":0,"k":[80,80,100],"ix":6}},"ao":0,"tm":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":90,"s":[2.637]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":180,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":270,"s":[2.637]},{"t":359,"s":[0]}],"ix":2},"w":1080,"h":1080,"ip":0,"op":367,"st":0,"bm":0}],"markers":[]}
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FF9800
4 | #000000
5 | #03DAC5
6 |
7 | #455A64
8 | #37474F
9 | #263238
10 | #000000
11 |
12 | #FAFAFA
13 | #E0E0E0
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/values/font_certs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - @array/com_google_android_gms_fonts_certs_dev
5 | - @array/com_google_android_gms_fonts_certs_prod
6 |
7 |
8 | -
9 | MIIEqDCCA5CgAwIBAgIJANWFuGx90071MA0GCSqGSIb3DQEBBAUAMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAeFw0wODA0MTUyMzM2NTZaFw0zNTA5MDEyMzM2NTZaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBANbOLggKv+IxTdGNs8/TGFy0PTP6DHThvbbR24kT9ixcOd9W+EaBPWW+wPPKQmsHxajtWjmQwWfna8mZuSeJS48LIgAZlKkpFeVyxW0qMBujb8X8ETrWy550NaFtI6t9+u7hZeTfHwqNvacKhp1RbE6dBRGWynwMVX8XW8N1+UjFaq6GCJukT4qmpN2afb8sCjUigq0GuMwYXrFVee74bQgLHWGJwPmvmLHC69EH6kWr22ijx4OKXlSIx2xT1AsSHee70w5iDBiK4aph27yH3TxkXy9V89TDdexAcKk/cVHYNnDBapcavl7y0RiQ4biu8ymM8Ga/nmzhRKya6G0cGw8CAQOjgfwwgfkwHQYDVR0OBBYEFI0cxb6VTEM8YYY6FbBMvAPyT+CyMIHJBgNVHSMEgcEwgb6AFI0cxb6VTEM8YYY6FbBMvAPyT+CyoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJANWFuGx90071MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBABnTDPEF+3iSP0wNfdIjIz1AlnrPzgAIHVvXxunW7SBrDhEglQZBbKJEk5kT0mtKoOD1JMrSu1xuTKEBahWRbqHsXclaXjoBADb0kkjVEJu/Lh5hgYZnOjvlba8Ld7HCKePCVePoTJBdI4fvugnL8TsgK05aIskyY0hKI9L8KfqfGTl1lzOv2KoWD0KWwtAWPoGChZxmQ+nBli+gwYMzM1vAkP+aayLe0a1EQimlOalO762r0GXO0ks+UeXde2Z4e+8S/pf7pITEI/tP+MxJTALw9QUWEv9lKTk+jkbqxbsh8nfBUapfKqYn0eidpwq2AzVp3juYl7//fKnaPhJD9gs=
10 |
11 |
12 |
13 | -
14 | MIIEQzCCAyugAwIBAgIJAMLgh0ZkSjCNMA0GCSqGSIb3DQEBBAUAMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDAeFw0wODA4MjEyMzEzMzRaFw0zNjAxMDcyMzEzMzRaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAKtWLgDYO6IIrgqWbxJOKdoR8qtW0I9Y4sypEwPpt1TTcvZApxsdyxMJZ2JORland2qSGT2y5b+3JKkedxiLDmpHpDsz2WCbdxgxRczfey5YZnTJ4VZbH0xqWVW/8lGmPav5xVwnIiJS6HXk+BVKZF+JcWjAsb/GEuq/eFdpuzSqeYTcfi6idkyugwfYwXFU1+5fZKUaRKYCwkkFQVfcAs1fXA5V+++FGfvjJ/CxURaSxaBvGdGDhfXE28LWuT9ozCl5xw4Yq5OGazvV24mZVSoOO0yZ31j7kYvtwYK6NeADwbSxDdJEqO4k//0zOHKrUiGYXtqw/A0LFFtqoZKFjnkCAQOjgdkwgdYwHQYDVR0OBBYEFMd9jMIhF1Ylmn/Tgt9r45jk14alMIGmBgNVHSMEgZ4wgZuAFMd9jMIhF1Ylmn/Tgt9r45jk14aloXikdjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLR29vZ2xlIEluYy4xEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMTB0FuZHJvaWSCCQDC4IdGZEowjTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4IBAQBt0lLO74UwLDYKqs6Tm8/yzKkEu116FmH4rkaymUIE0P9KaMftGlMexFlaYjzmB2OxZyl6euNXEsQH8gjwyxCUKRJNexBiGcCEyj6z+a1fuHHvkiaai+KL8W1EyNmgjmyy8AW7P+LLlkR+ho5zEHatRbM/YAnqGcFh5iZBqpknHf1SKMXFh4dd239FJ1jWYfbMDMy3NS5CTMQ2XFI1MvcyUTdZPErjQfTbQe3aDQsQcafEQPD+nqActifKZ0Np0IS9L9kR/wbNvyz6ENwPiTrjV2KRkEjH78ZMcUQXg0L3BYHJ3lc69Vs5Ddf9uUGGMYldX3WfMBEmh/9iFBDAaTCK
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #000000
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/preloaded_fonts.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - @font/lato
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Onboarder
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext {
3 | kotlin_version = '1.9.21'
4 | }
5 | repositories {
6 | google()
7 | mavenCentral()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:8.2.0'
11 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | google()
18 | mavenCentral()
19 | }
20 | }
21 |
22 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
19 |
20 | android.enableJetifier=true
21 | android.useAndroidX=true
22 | support_library_version = 26.0.1
23 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akshaaatt/Onboarding-Android/e5c7187a9fdc99a03621a0df1bf00f875e34388c/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Oct 05 13:53:12 CEST 2023
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
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 |
--------------------------------------------------------------------------------
/jitpack.yml:
--------------------------------------------------------------------------------
1 | jdk:
2 | - openjdk17
--------------------------------------------------------------------------------
/local.properties:
--------------------------------------------------------------------------------
1 | ## This file must *NOT* be checked into Version Control Systems,
2 | # as it contains information specific to your local configuration.
3 | #
4 | # Location of the SDK. This is only used by Gradle.
5 | # For customization when using a Version Control System, please read the
6 | # header note.
7 | #Thu Jul 07 15:08:42 IST 2022
8 | sdk.dir=/Users/avataar/Library/Android/sdk
9 |
--------------------------------------------------------------------------------
/onboard/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'kotlin-android'
4 | id 'maven-publish'
5 | }
6 |
7 | android {
8 | namespace 'com.limurse.onboard'
9 |
10 | compileSdk 34
11 | defaultConfig {
12 | minSdk 17
13 | targetSdk 34
14 |
15 | consumerProguardFiles 'consumer-proguard-rules.pro'
16 | vectorDrawables.useSupportLibrary = true
17 | }
18 |
19 | compileOptions {
20 | sourceCompatibility JavaVersion.VERSION_17
21 | targetCompatibility JavaVersion.VERSION_17
22 | }
23 | kotlinOptions {
24 | jvmTarget = '17'
25 | }
26 | }
27 |
28 | dependencies {
29 | implementation 'androidx.appcompat:appcompat:1.6.1'
30 | implementation 'androidx.annotation:annotation:1.7.1'
31 | implementation 'com.airbnb.android:lottie:6.2.0'
32 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
33 | implementation 'com.google.android.gms:play-services-base:18.2.0'
34 |
35 | testImplementation 'junit:junit:4.13.2'
36 | testImplementation 'org.mockito:mockito-core:5.8.0'
37 | }
38 |
39 | afterEvaluate {
40 | publishing {
41 | publications {
42 | // Creates a Maven publication called "release".
43 | release(MavenPublication) {
44 | // Applies the component for the release build variant.
45 | from components.release
46 |
47 | // You can then customize attributes of the publication as shown below.
48 | groupId = 'com.limurse'
49 | artifactId = 'Omboard'
50 | version = '1.1.3'
51 | }
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/onboard/consumer-proguard-rules.pro:
--------------------------------------------------------------------------------
1 | -keep class com.limurse.onboard.** {*;}
2 |
--------------------------------------------------------------------------------
/onboard/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=Onboard
2 | GROUP=com.limurse.onboard
3 | POM_NAME=Onboard
4 | POM_DESCRIPTION=Make a cool intro for your Android app.
5 | POM_URL=git://github.com/Onboard/Onboard.git
6 | POM_SCM_URL=https://github.com/Onboard/Onboard
7 | POM_SCM_CONNECTION=scm:git://github.com/Onboard/Onboard.git
8 | POM_SCM_DEV_CONNECTION=scm:git://github.com/Onboard/Onboard.git
9 | POM_LICENSE_NAME=The Apache Software License, Version 2.0
10 | POM_LICENSE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt
11 |
--------------------------------------------------------------------------------
/onboard/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/onboard/src/main/java/com/limurse/onboard/OnboardAdvanced.kt:
--------------------------------------------------------------------------------
1 | package com.limurse.onboard
2 |
3 | import android.graphics.drawable.Drawable
4 | import android.os.Bundle
5 | import android.view.View
6 | import android.view.View.GONE
7 | import android.view.View.VISIBLE
8 | import android.widget.ImageButton
9 | import androidx.annotation.ColorInt
10 | import androidx.annotation.IdRes
11 | import androidx.appcompat.widget.AppCompatButton
12 | import androidx.constraintlayout.widget.ConstraintLayout
13 |
14 | abstract class OnboardAdvanced : OnboardBase() {
15 |
16 | override val layoutId = R.layout.onboard_intro_layout2
17 |
18 | @IdRes
19 | var backgroundResource: Int? = null
20 | set(value) {
21 | field = value
22 | if (field != null) {
23 | field?.let { backgroundFrame.setBackgroundResource(it) }
24 | }
25 | }
26 |
27 | var backgroundDrawable: Drawable? = null
28 | set(value) {
29 | field = value
30 | if (field != null) {
31 | backgroundFrame.background = field
32 | }
33 | }
34 |
35 | private lateinit var backgroundFrame: ConstraintLayout
36 | private lateinit var bottomBar: View
37 | private lateinit var skipImageButton: ImageButton
38 | private lateinit var signInButton: AppCompatButton
39 |
40 | override fun onCreate(savedInstanceState: Bundle?) {
41 | super.onCreate(savedInstanceState)
42 | backgroundFrame = findViewById(R.id.background)
43 | bottomBar = findViewById(R.id.bottom)
44 | skipImageButton = findViewById(R.id.skip)
45 | signInButton = findViewById(R.id.sign_in_button)
46 | if (isRtl) {
47 | skipImageButton.scaleX = -1F
48 | }
49 | }
50 |
51 | /**
52 | * Override viewpager bar color
53 | * @param color your color resource
54 | */
55 | fun setBarColor(@ColorInt color: Int) {
56 | bottomBar.setBackgroundColor(color)
57 | }
58 |
59 | fun setSignInButtonColor(@ColorInt color : Int) {
60 | signInButton.setBackgroundColor(color)
61 | }
62 |
63 | fun setSignInButton(show: Boolean){
64 | when {
65 | show -> {
66 | signInButton.visibility = VISIBLE
67 | }
68 | else -> {
69 | signInButton.visibility = GONE
70 | }
71 | }
72 | }
73 |
74 |
75 |
76 | /**
77 | * Override Skip button drawable
78 | * @param imageSkipButton your drawable resource
79 | */
80 | fun setImageSkipButton(imageSkipButton: Drawable) {
81 | skipImageButton.setImageDrawable(imageSkipButton)
82 | }
83 |
84 | /**
85 | * Override next button arrow color
86 | *
87 | * @param color your color
88 | */
89 | fun setNextArrowColor(@ColorInt color: Int) {
90 | val nextButton = findViewById(R.id.next)
91 | nextButton.setColorFilter(color)
92 | }
93 |
94 | /**
95 | * Override skip button color
96 | *
97 | * @param colorSkipButton your color resource
98 | */
99 | fun setSkipArrowColor(@ColorInt colorSkipButton: Int) {
100 | val skip = findViewById(R.id.skip)
101 | skip.setColorFilter(colorSkipButton)
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/onboard/src/main/java/com/limurse/onboard/OnboardBaseFragment.kt:
--------------------------------------------------------------------------------
1 | package com.limurse.onboard
2 |
3 | import android.graphics.drawable.Animatable
4 | import android.os.Bundle
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.View.GONE
8 | import android.view.View.VISIBLE
9 | import android.view.ViewGroup
10 | import android.widget.ImageView
11 | import android.widget.TextView
12 | import androidx.annotation.ColorInt
13 | import androidx.annotation.LayoutRes
14 | import androidx.constraintlayout.widget.ConstraintLayout
15 | import androidx.fragment.app.Fragment
16 | import com.airbnb.lottie.LottieAnimationView
17 | import com.limurse.onboard.internal.LogHelper
18 | import com.limurse.onboard.internal.TypefaceContainer
19 |
20 | internal const val ARG_TITLE = "title"
21 | internal const val ARG_TITLE_TYPEFACE = "title_typeface"
22 | internal const val ARG_TITLE_TYPEFACE_RES = "title_typeface_res"
23 | internal const val ARG_DESC = "desc"
24 | internal const val ARG_DESC_TYPEFACE = "desc_typeface"
25 | internal const val ARG_DESC_TYPEFACE_RES = "desc_typeface_res"
26 | internal const val ARG_DRAWABLE = "drawable"
27 | internal const val ARG_BG_COLOR = "bg_color"
28 | internal const val ARG_TITLE_COLOR = "title_color"
29 | internal const val ARG_DESC_COLOR = "desc_color"
30 | internal const val ARG_BG_DRAWABLE = "bg_drawable"
31 | internal const val IS_LOTTIE = "is_lottie"
32 |
33 | abstract class OnboardBaseFragment : Fragment(), SlideSelectionListener, SlideBackgroundColorHolder {
34 |
35 | private val logTAG = LogHelper.makeLogTag(OnboardBaseFragment::class.java)
36 |
37 | @get:LayoutRes
38 | protected abstract val layoutId: Int
39 |
40 | private var resourceId: Int = 0
41 | private var bgDrawable: Int = 0
42 |
43 | private var titleColor: Int = 0
44 | private var descColor: Int = 0
45 | final override var defaultBackgroundColor: Int = 0
46 | private set
47 |
48 | private var title: String? = null
49 | private var description: String? = null
50 | private var isLottie: Boolean = false
51 | private var titleTypeface: TypefaceContainer? = null
52 | private var descTypeface: TypefaceContainer? = null
53 |
54 | override fun onCreate(savedInstanceState: Bundle?) {
55 | super.onCreate(savedInstanceState)
56 | retainInstance = true
57 |
58 | val args = arguments
59 | if (args != null && args.size() != 0) {
60 | resourceId = args.getInt(ARG_DRAWABLE)
61 | title = args.getString(ARG_TITLE)
62 | description = args.getString(ARG_DESC)
63 | bgDrawable = args.getInt(ARG_BG_DRAWABLE)
64 | isLottie = args.getBoolean(IS_LOTTIE)
65 |
66 | val argsTitleTypeface = args.getString(ARG_TITLE_TYPEFACE)
67 | val argsDescTypeface = args.getString(ARG_DESC_TYPEFACE)
68 | val argsTitleTypefaceRes = args.getInt(ARG_TITLE_TYPEFACE_RES)
69 | val argsDescTypefaceRes = args.getInt(ARG_DESC_TYPEFACE_RES)
70 | titleTypeface = TypefaceContainer(argsTitleTypeface, argsTitleTypefaceRes)
71 | descTypeface = TypefaceContainer(argsDescTypeface, argsDescTypefaceRes)
72 |
73 | defaultBackgroundColor = args.getInt(ARG_BG_COLOR)
74 | titleColor = args.getInt(ARG_TITLE_COLOR, 0)
75 | descColor = args.getInt(ARG_DESC_COLOR, 0)
76 | }
77 | }
78 |
79 | override fun onActivityCreated(savedInstanceState: Bundle?) {
80 | super.onActivityCreated(savedInstanceState)
81 |
82 | if (savedInstanceState != null) {
83 | resourceId = savedInstanceState.getInt(ARG_DRAWABLE)
84 | title = savedInstanceState.getString(ARG_TITLE)
85 | description = savedInstanceState.getString(ARG_DESC)
86 | isLottie = savedInstanceState.getBoolean(IS_LOTTIE)
87 |
88 | titleTypeface = TypefaceContainer(
89 | savedInstanceState.getString(ARG_TITLE_TYPEFACE),
90 | savedInstanceState.getInt(ARG_TITLE_TYPEFACE_RES, 0)
91 | )
92 | descTypeface = TypefaceContainer(
93 | savedInstanceState.getString(ARG_DESC_TYPEFACE),
94 | savedInstanceState.getInt(ARG_DESC_TYPEFACE_RES, 0)
95 | )
96 |
97 | defaultBackgroundColor = savedInstanceState.getInt(ARG_BG_COLOR)
98 | bgDrawable = savedInstanceState.getInt(ARG_BG_DRAWABLE)
99 | titleColor = savedInstanceState.getInt(ARG_TITLE_COLOR)
100 | descColor = savedInstanceState.getInt(ARG_DESC_COLOR)
101 | }
102 | }
103 |
104 | override fun onCreateView(
105 | inflater: LayoutInflater,
106 | container: ViewGroup?,
107 | savedInstanceState: Bundle?
108 | ): View? {
109 | val view = inflater.inflate(layoutId, container, false)
110 | val titleText = view.findViewById(R.id.title)
111 | val descriptionText = view.findViewById(R.id.description)
112 | val slideImage = view.findViewById(R.id.image)
113 | val mainLayout = view.findViewById(R.id.main)
114 | val animationView = view.findViewById(R.id.animation_view)
115 |
116 | titleText.text = title
117 | descriptionText.text = description
118 | if (titleColor != 0) {
119 | titleText.setTextColor(titleColor)
120 | }
121 | if (descColor != 0) {
122 | descriptionText.setTextColor(descColor)
123 | }
124 | if(isLottie){
125 | slideImage.visibility = GONE
126 | animationView.visibility = VISIBLE
127 | animationView.setAnimation(resourceId)
128 | }
129 | else{
130 | slideImage.visibility = VISIBLE
131 | animationView.visibility = GONE
132 | slideImage.setImageResource(resourceId)
133 | }
134 | titleTypeface?.applyTo(titleText)
135 | descTypeface?.applyTo(descriptionText)
136 |
137 | if (bgDrawable != 0) {
138 | mainLayout?.setBackgroundResource(bgDrawable)
139 | } else {
140 | mainLayout?.setBackgroundColor(defaultBackgroundColor)
141 | }
142 |
143 | return view
144 | }
145 |
146 | override fun onResume() {
147 | super.onResume()
148 |
149 | view?.findViewById(R.id.image).let {
150 | if (it is Animatable) {
151 | it.start()
152 | }
153 | }
154 | }
155 |
156 | override fun onPause() {
157 | super.onPause()
158 |
159 | view?.findViewById(R.id.image).let {
160 | if (it is Animatable) {
161 | it.start()
162 | }
163 | }
164 | }
165 |
166 | override fun onSaveInstanceState(outState: Bundle) {
167 | outState.putInt(ARG_DRAWABLE, resourceId)
168 | outState.putInt(ARG_BG_DRAWABLE, bgDrawable)
169 | outState.putString(ARG_TITLE, title)
170 | outState.putString(ARG_DESC, description)
171 | outState.putInt(ARG_BG_COLOR, defaultBackgroundColor)
172 | outState.putInt(ARG_TITLE_COLOR, titleColor)
173 | outState.putInt(ARG_DESC_COLOR, descColor)
174 | outState.putBoolean(IS_LOTTIE,isLottie)
175 | if (titleTypeface != null) {
176 | outState.putString(ARG_TITLE_TYPEFACE, titleTypeface?.typeFaceUrl)
177 | outState.putInt(ARG_TITLE_TYPEFACE_RES, titleTypeface?.typeFaceResource ?: 0)
178 | }
179 | if (descTypeface != null) {
180 | outState.putString(ARG_DESC_TYPEFACE, descTypeface?.typeFaceUrl)
181 | outState.putInt(ARG_DESC_TYPEFACE_RES, descTypeface?.typeFaceResource ?: 0)
182 | }
183 | super.onSaveInstanceState(outState)
184 | }
185 |
186 | override fun onSlideDeselected() {
187 | LogHelper.d(logTAG, "Slide $title has been deselected.")
188 | }
189 |
190 | override fun onSlideSelected() {
191 | LogHelper.d(logTAG, "Slide $title has been selected.")
192 | }
193 |
194 | override fun setBackgroundColor(@ColorInt backgroundColor: Int) {
195 | view?.findViewById(R.id.main)?.setBackgroundColor(backgroundColor)
196 | }
197 | }
198 |
--------------------------------------------------------------------------------
/onboard/src/main/java/com/limurse/onboard/OnboardCustomLayoutFragment.kt:
--------------------------------------------------------------------------------
1 | package com.limurse.onboard
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import androidx.fragment.app.Fragment
8 |
9 | /**
10 | * Util class to be used when creating a slide with a custom layout.
11 | * [OnboardCustomLayoutFragment.newInstance] passing the Layout ID of your custom layout.
12 | *
13 | * You can then use this Slide with the [OnboardBase.addSlide] methods to add this slide
14 | * to your Onboard.
15 | */
16 | class OnboardCustomLayoutFragment : Fragment() {
17 |
18 | private var layoutResId = 0
19 |
20 | override fun onCreate(savedInstanceState: Bundle?) {
21 | super.onCreate(savedInstanceState)
22 | layoutResId = arguments?.getInt(ARG_LAYOUT_RES_ID) ?: 0
23 | }
24 |
25 | override fun onCreateView(
26 | inflater: LayoutInflater,
27 | container: ViewGroup?,
28 | savedInstanceState: Bundle?
29 | ): View? = inflater.inflate(layoutResId, container, false)
30 |
31 | companion object {
32 | private const val ARG_LAYOUT_RES_ID = "layoutResId"
33 | @JvmStatic
34 | fun newInstance(layoutResId: Int): OnboardCustomLayoutFragment {
35 | val customSlide = OnboardCustomLayoutFragment()
36 | val args = Bundle()
37 | args.putInt(ARG_LAYOUT_RES_ID, layoutResId)
38 | customSlide.arguments = args
39 | return customSlide
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/onboard/src/main/java/com/limurse/onboard/OnboardFragment.kt:
--------------------------------------------------------------------------------
1 | package com.limurse.onboard
2 |
3 | import androidx.annotation.ColorInt
4 | import androidx.annotation.DrawableRes
5 | import androidx.annotation.FontRes
6 | import com.limurse.onboard.model.SliderPage
7 |
8 | @Suppress("LongParameterList")
9 | class OnboardFragment : OnboardBaseFragment() {
10 |
11 | override val layoutId: Int get() = R.layout.onboard_fragment_intro
12 |
13 | companion object {
14 |
15 | /**
16 | * Generates a new instance for [OnboardFragment]
17 | *
18 | * @param title CharSequence which will be the slide title
19 | * @param description CharSequence which will be the slide description
20 | * @param resourceId @DrawableRes (Integer) the image that will be
21 | * displayed, obtained from Resources
22 | * @param backgroundColor @ColorInt (Integer) custom background color
23 | * @param titleColor @ColorInt (Integer) custom title color
24 | * @param descriptionColor @ColorInt (Integer) custom description color
25 | * @param titleTypefaceFontRes @FontRes (Integer) custom title typeface obtained
26 | * from Resources
27 | * @param descriptionTypefaceFontRes @FontRes (Integer) custom description typeface obtained
28 | * from Resources
29 | * @param backgroundDrawable @DrawableRes (Integer) custom background drawable
30 | *
31 | * @return An [OnboardFragment] created instance
32 | */
33 | @JvmOverloads
34 | @JvmStatic
35 | fun newInstance(
36 | title: CharSequence? = null,
37 | description: CharSequence? = null,
38 | resourceId: Int = 0,
39 | @ColorInt backgroundColor: Int = 0,
40 | @ColorInt titleColor: Int = 0,
41 | @ColorInt descriptionColor: Int = 0,
42 | @FontRes titleTypefaceFontRes: Int = 0,
43 | @FontRes descriptionTypefaceFontRes: Int = 0,
44 | @DrawableRes backgroundDrawable: Int = 0,
45 | isLottie: Boolean = false
46 | ): OnboardFragment {
47 | return newInstance(
48 | SliderPage(
49 | title = title,
50 | description = description,
51 | resourceId = resourceId,
52 | backgroundColor = backgroundColor,
53 | titleColor = titleColor,
54 | descriptionColor = descriptionColor,
55 | titleTypefaceFontRes = titleTypefaceFontRes,
56 | descriptionTypefaceFontRes = descriptionTypefaceFontRes,
57 | backgroundDrawable = backgroundDrawable,
58 | isLottie = isLottie
59 | )
60 | )
61 | }
62 |
63 | /**
64 | * Generates an [OnboardFragment] from a given [SliderPage]
65 | *
66 | * @param sliderPage the [SliderPage] object which contains all attributes for
67 | * the current slide
68 | *
69 | * @return An [OnboardFragment] created instance
70 | */
71 | @JvmStatic
72 | fun newInstance(sliderPage: SliderPage): OnboardFragment {
73 | val slide = OnboardFragment()
74 | slide.arguments = sliderPage.toBundle()
75 | return slide
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/onboard/src/main/java/com/limurse/onboard/OnboardLegacy.kt:
--------------------------------------------------------------------------------
1 | package com.limurse.onboard
2 |
3 | import android.graphics.drawable.Drawable
4 | import android.view.View
5 | import android.widget.ImageButton
6 | import android.widget.ImageView
7 | import android.widget.TextView
8 | import androidx.annotation.ColorInt
9 | import androidx.annotation.FontRes
10 | import androidx.annotation.StringRes
11 | import androidx.annotation.StyleRes
12 | import androidx.core.widget.TextViewCompat
13 | import com.limurse.onboard.internal.TypefaceContainer
14 |
15 | abstract class OnboardLegacy : com.limurse.onboard.OnboardBase() {
16 |
17 | override val layoutId = R.layout.onboard_intro_layout
18 |
19 | /**
20 | * Override viewpager bar color
21 | * @param color your color resource
22 | */
23 | fun setBarColor(@ColorInt color: Int) {
24 | val bottomBar = findViewById(R.id.bottom)
25 | bottomBar.setBackgroundColor(color)
26 | }
27 |
28 | /**
29 | * Override next button arrow color
30 | *
31 | * @param color your color
32 | */
33 | fun setNextArrowColor(@ColorInt color: Int) {
34 | val nextButton = findViewById(R.id.next)
35 | nextButton.setColorFilter(color)
36 | }
37 |
38 | /**
39 | * Override back button arrow color
40 | *
41 | * @param color your color
42 | */
43 | fun setBackArrowColor(@ColorInt color: Int) {
44 | val backButton = findViewById(R.id.back)
45 | backButton.setColorFilter(color)
46 | }
47 |
48 | /**
49 | * Override separator color
50 | *
51 | * @param color your color resource
52 | */
53 | fun setSeparatorColor(@ColorInt color: Int) {
54 | val separator = findViewById(R.id.bottom_separator)
55 | separator.setBackgroundColor(color)
56 | }
57 |
58 | /**
59 | * Override skip text
60 | *
61 | * @param text your text
62 | */
63 | fun setSkipText(text: CharSequence?) {
64 | val skipText = findViewById(R.id.skip)
65 | skipText.text = text
66 | }
67 |
68 | /**
69 | * Override skip text
70 | *
71 | * @param skipResId your text resource Id
72 | */
73 | fun setSkipText(@StringRes skipResId: Int) {
74 | val skipText = findViewById(R.id.skip)
75 | skipText.setText(skipResId)
76 | }
77 |
78 | /**
79 | * Override skip text typeface
80 | *
81 | * @param typeface the typeface to apply to Skip button
82 | */
83 | fun setSkipTextTypeface(@FontRes typeface: Int) {
84 | val view = findViewById(R.id.skip)
85 | TypefaceContainer(null, typeface).applyTo(view)
86 | }
87 |
88 | /**
89 | * Override skip text typeface
90 | *
91 | * @param typeURL URL of font file located in Assets folder
92 | */
93 | fun setSkipTextTypeface(typeURL: String?) {
94 | val view = findViewById(R.id.skip)
95 | TypefaceContainer(typeURL, 0).applyTo(view)
96 | }
97 |
98 | /**
99 | * Override done text
100 | *
101 | * @param text your text
102 | */
103 | fun setDoneText(text: CharSequence?) {
104 | val doneText = findViewById(R.id.done)
105 | doneText.text = text
106 | }
107 |
108 | /**
109 | * Override done text
110 | *
111 | * @param doneResId your text resource Id
112 | */
113 | fun setDoneText(@StringRes doneResId: Int) {
114 | val doneText = findViewById(R.id.done)
115 | doneText.setText(doneResId)
116 | }
117 |
118 | /**
119 | * Override done text typeface
120 | *
121 | * @param typeURL URL of font file located in Assets folder
122 | */
123 | fun setDoneTextTypeface(typeURL: String?) {
124 | val view = findViewById(R.id.done)
125 | TypefaceContainer(typeURL, 0).applyTo(view)
126 | }
127 |
128 | /**
129 | * Override done text typeface
130 | *
131 | * @param typeface the typeface to apply to Done button
132 | */
133 | fun setDoneTextTypeface(@FontRes typeface: Int) {
134 | val view = findViewById(R.id.done)
135 | TypefaceContainer(null, typeface).applyTo(view)
136 | }
137 |
138 | /**
139 | * Override done button text color
140 | *
141 | * @param colorDoneText your color resource
142 | */
143 | fun setColorDoneText(@ColorInt colorDoneText: Int) {
144 | val doneText = findViewById(R.id.done)
145 | doneText.setTextColor(colorDoneText)
146 | }
147 |
148 | /**
149 | * Override done button text overall style
150 | *
151 | * @param textAppearance your text style from resource
152 | */
153 | fun setDoneTextAppearance(@StyleRes textAppearance: Int) {
154 | val doneText = findViewById(R.id.done)
155 | TextViewCompat.setTextAppearance(doneText, textAppearance)
156 | }
157 |
158 | /**
159 | * Override skip button color
160 | *
161 | * @param colorSkipButton your color resource
162 | */
163 | fun setColorSkipButton(@ColorInt colorSkipButton: Int) {
164 | val skip = findViewById(R.id.skip)
165 | skip.setTextColor(colorSkipButton)
166 | }
167 |
168 | /**
169 | * Override skip button text overall style
170 | *
171 | * @param textAppearance your text style from resource
172 | */
173 | fun setSkipTextAppearance(@StyleRes textAppearance: Int) {
174 | val skip = findViewById(R.id.skip)
175 | TextViewCompat.setTextAppearance(skip, textAppearance)
176 | }
177 |
178 | /**
179 | * Override Next button
180 | *
181 | * @param imageNextButton your drawable resource
182 | */
183 | fun setImageNextButton(imageNextButton: Drawable) {
184 | val nextButton = findViewById(R.id.next)
185 | nextButton.setImageDrawable(imageNextButton)
186 | }
187 |
188 | /**
189 | * Show or hide the Separator line.
190 | * This is a static setting and Separator state is maintained across slides
191 | * until explicitly changed.
192 | *
193 | * @param showSeparator Set : true to display. false to hide.
194 | */
195 | fun showSeparator(showSeparator: Boolean) {
196 | val bottomSeparator = findViewById(R.id.bottom_separator)
197 | if (showSeparator) {
198 | bottomSeparator.visibility = View.VISIBLE
199 | } else {
200 | bottomSeparator.visibility = View.INVISIBLE
201 | }
202 | }
203 | }
204 |
--------------------------------------------------------------------------------
/onboard/src/main/java/com/limurse/onboard/OnboardPageTransformerType.kt:
--------------------------------------------------------------------------------
1 | package com.limurse.onboard
2 |
3 | /**
4 | * Sealed class to represent all the possible Page Transformers
5 | * offered by Onboard.
6 | */
7 | sealed class OnboardPageTransformerType {
8 |
9 | /** Sets the animation of the intro to a flow animation */
10 | object Flow : OnboardPageTransformerType()
11 |
12 | /** Sets the animation of the intro to a depth animation */
13 | object Depth : OnboardPageTransformerType()
14 |
15 | /** Sets the animation of the intro to a zoom animation */
16 | object Zoom : OnboardPageTransformerType()
17 |
18 | /** Sets the animation of the intro to a slide over animation */
19 | object SlideOver : OnboardPageTransformerType()
20 |
21 | /** Sets the animation of the intro to a fade animation */
22 | object Fade : OnboardPageTransformerType()
23 |
24 | /**
25 | * Sets the animation of the intro to a parallax animation
26 | * @property titleParallaxFactor Parallax factor of title
27 | * @property imageParallaxFactor Parallax factor of image
28 | * @property descriptionParallaxFactor Parallax factor of description
29 | */
30 | class Parallax(
31 | val titleParallaxFactor: Double = 1.0,
32 | val imageParallaxFactor: Double = -1.0,
33 | val descriptionParallaxFactor: Double = 2.0
34 | ) : OnboardPageTransformerType()
35 | }
36 |
--------------------------------------------------------------------------------
/onboard/src/main/java/com/limurse/onboard/OnboardViewPagerListener.kt:
--------------------------------------------------------------------------------
1 | package com.limurse.onboard
2 |
3 | /**
4 | * Register an instance of OnboardViewPagerListener.
5 | * Before the user swipes to the next page, this listener will be called and
6 | * can interrupt swiping by returning false to [onCanRequestNextPage]
7 | *
8 | * [onIllegallyRequestedNextPage] will be called if the user tries to swipe and was not allowed
9 | * to do so (useful for showing a toast or something similar).
10 | *
11 | * [onUserRequestedPermissionsDialog] will be called when the user swipes forward on a slide
12 | * that contains permissions.
13 | */
14 | interface OnboardViewPagerListener {
15 | fun onCanRequestNextPage(): Boolean
16 |
17 | fun onIllegallyRequestedNextPage()
18 |
19 | fun onUserRequestedPermissionsDialog()
20 | }
21 |
--------------------------------------------------------------------------------
/onboard/src/main/java/com/limurse/onboard/SlideBackgroundColorHolder.kt:
--------------------------------------------------------------------------------
1 | package com.limurse.onboard
2 |
3 | import androidx.annotation.ColorInt
4 |
5 | interface SlideBackgroundColorHolder {
6 |
7 | /**
8 | * Returns the default background color of the slide
9 | *
10 | * @return The default background color of the slide
11 | */
12 | @get:ColorInt
13 | val defaultBackgroundColor: Int
14 |
15 | /**
16 | * Sets the actual background color of the slide. This does not affect the default background color.
17 | * This method should change the background color of the slide's root layout element (e.g. LinearLayout).
18 | *
19 | * @param backgroundColor New actual background color.
20 | */
21 | fun setBackgroundColor(@ColorInt backgroundColor: Int)
22 | }
23 |
--------------------------------------------------------------------------------
/onboard/src/main/java/com/limurse/onboard/SlidePolicy.kt:
--------------------------------------------------------------------------------
1 | package com.limurse.onboard
2 |
3 | interface SlidePolicy {
4 |
5 | /**
6 | * Whether the user has fulfilled the slides policy and should be allowed to navigate through the intro further.
7 | * If false is returned, [.onUserIllegallyRequestedNextPage] will be called.
8 | *
9 | * @return True if the user should be allowed to leave the slide, else false.
10 | */
11 | val isPolicyRespected: Boolean
12 |
13 | /**
14 | * Called if a user tries to go to the next slide while into navigation has been locked.
15 | */
16 | fun onUserIllegallyRequestedNextPage()
17 | }
18 |
--------------------------------------------------------------------------------
/onboard/src/main/java/com/limurse/onboard/SlideSelectionListener.kt:
--------------------------------------------------------------------------------
1 | package com.limurse.onboard
2 |
3 | interface SlideSelectionListener {
4 | /**
5 | * Called when this slide becomes selected
6 | */
7 | fun onSlideSelected()
8 |
9 | /**
10 | * Called when this slide gets deselected.
11 | * Please note, that this method won't be called if the user exits the intro in any way.
12 | */
13 | fun onSlideDeselected()
14 | }
15 |
--------------------------------------------------------------------------------
/onboard/src/main/java/com/limurse/onboard/indicator/DotIndicatorController.kt:
--------------------------------------------------------------------------------
1 | package com.limurse.onboard.indicator
2 |
3 | import android.content.Context
4 | import android.view.Gravity
5 | import android.view.Gravity.CENTER
6 | import android.view.View
7 | import android.widget.ImageView
8 | import android.widget.LinearLayout
9 | import androidx.core.content.ContextCompat
10 | import androidx.core.graphics.drawable.DrawableCompat
11 | import com.limurse.onboard.R
12 |
13 | /**
14 | * An [IndicatorController] that shows a list of dots and highlight the selected dot.
15 | * Use this when the number of page you're dealing with is not too high.
16 | */
17 | class DotIndicatorController(context: Context) : IndicatorController, LinearLayout(context) {
18 |
19 | override var selectedIndicatorColor = ContextCompat.getColor(context, R.color.onboard_default_selected_color)
20 | set(value) {
21 | field = value
22 | selectPosition(currentPosition)
23 | }
24 |
25 | override var unselectedIndicatorColor = ContextCompat.getColor(context, R.color.onboard_default_unselected_color)
26 | set(value) {
27 | field = value
28 | selectPosition(currentPosition)
29 | }
30 |
31 | private var currentPosition = 0
32 | private var slideCount = 0
33 |
34 | override fun newInstance(context: Context): View {
35 | val newLayoutParams = LayoutParams(
36 | LayoutParams.WRAP_CONTENT,
37 | LayoutParams.MATCH_PARENT
38 | )
39 | newLayoutParams.gravity = Gravity.CENTER_VERTICAL
40 | layoutParams = newLayoutParams
41 | orientation = HORIZONTAL
42 | gravity = CENTER
43 | return this
44 | }
45 |
46 | override fun initialize(slideCount: Int) {
47 | this.slideCount = slideCount
48 | for (i in 0 until slideCount) {
49 | val dot = ImageView(this.context)
50 | dot.setImageDrawable(
51 | ContextCompat.getDrawable(this.context, R.drawable.ic_onboard_indicator)
52 | )
53 | val params = LayoutParams(
54 | LayoutParams.WRAP_CONTENT,
55 | LayoutParams.WRAP_CONTENT
56 | )
57 | if (slideCount == 1) {
58 | dot.visibility = View.INVISIBLE
59 | }
60 | this.addView(dot, params)
61 | }
62 | selectPosition(0)
63 | }
64 |
65 | override fun selectPosition(index: Int) {
66 | currentPosition = index
67 | for (i in 0 until slideCount) {
68 | val tint = if (i == index) {
69 | selectedIndicatorColor
70 | } else {
71 | unselectedIndicatorColor
72 | }
73 | (getChildAt(i) as ImageView).let { DrawableCompat.setTint(it.drawable, tint) }
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/onboard/src/main/java/com/limurse/onboard/indicator/IndicatorController.kt:
--------------------------------------------------------------------------------
1 | package com.limurse.onboard.indicator
2 |
3 | import android.content.Context
4 | import android.view.View
5 | import androidx.annotation.ColorInt
6 |
7 | /**
8 | * A controller that is used to provide custom indicator implementations and to control
9 | * their behaviour. This is used for [Onboard.setCustomIndicator] and
10 | * [Onboard2.setCustomIndicator]
11 | */
12 | interface IndicatorController {
13 |
14 | @get:ColorInt
15 | var selectedIndicatorColor: Int
16 |
17 | @get:ColorInt
18 | var unselectedIndicatorColor: Int
19 |
20 | /**
21 | * Create a new instance of the view to be inserted in the Onboard layout.
22 | * This method is only called once for each creation of the activity.
23 | *
24 | * [IndicatorController.initialize] is called after this.
25 | *
26 | * @param context A context to be used for the view instantiation
27 | * @return An instance of the indicator view
28 | */
29 | fun newInstance(context: Context): View
30 |
31 | /**
32 | * Initialize the indicator view with the requested amount of elements.
33 | * As with [IndicatorController.newInstance], this method is only called once for each
34 | * creation of the activity as well.
35 | *
36 | * [IndicatorController.newInstance] is called before this.
37 | *
38 | * @param slideCount The amount of slides present in the Onboard
39 | */
40 | fun initialize(slideCount: Int)
41 |
42 | /**
43 | * Select the position for the new page that became selected.
44 | * This method is called every time the selected page changed.
45 | *
46 | * @param index The index of the page that became selected
47 | */
48 | fun selectPosition(index: Int)
49 | }
50 |
--------------------------------------------------------------------------------
/onboard/src/main/java/com/limurse/onboard/indicator/ProgressIndicatorController.kt:
--------------------------------------------------------------------------------
1 | package com.limurse.onboard.indicator
2 |
3 | import android.content.Context
4 | import android.graphics.PorterDuff
5 | import android.util.AttributeSet
6 | import android.view.View
7 | import android.widget.ProgressBar
8 | import com.limurse.onboard.internal.LayoutUtil
9 |
10 | internal const val DEFAULT_COLOR = 1
11 |
12 | /**
13 | * An [IndicatorController] that shows a [ProgressBar] for express the number of
14 | * page that have been completed.
15 | * Use this when the number of page is higher and the [DotIndicatorController]
16 | * would not fit in the screen.
17 | */
18 | class ProgressIndicatorController @JvmOverloads constructor(
19 | context: Context,
20 | attrs: AttributeSet? = null,
21 | defStyleAttr: Int = android.R.attr.progressBarStyleHorizontal
22 | ) : IndicatorController, ProgressBar(context, attrs, defStyleAttr) {
23 |
24 | override var selectedIndicatorColor = DEFAULT_COLOR
25 | set(value) {
26 | field = value
27 | progressDrawable.setColorFilter(value, PorterDuff.Mode.SRC_IN)
28 | }
29 |
30 | override var unselectedIndicatorColor = DEFAULT_COLOR
31 | set(value) {
32 | field = value
33 | indeterminateDrawable.setColorFilter(value, PorterDuff.Mode.SRC_IN)
34 | }
35 |
36 | override fun newInstance(context: Context) = this
37 |
38 | override fun initialize(slideCount: Int) {
39 | this.max = slideCount
40 | if (isRtl) {
41 | this.scaleX = -1F
42 | }
43 | if (slideCount == 1) {
44 | this.visibility = View.INVISIBLE
45 | }
46 | selectPosition(0)
47 | }
48 |
49 | override fun selectPosition(index: Int) {
50 | this.progress = if (isRtl) { max - index } else { index + 1 }
51 | }
52 |
53 | private val isRtl: Boolean get() = LayoutUtil.isRtl(this.context)
54 | }
55 |
--------------------------------------------------------------------------------
/onboard/src/main/java/com/limurse/onboard/internal/CustomFontCache.kt:
--------------------------------------------------------------------------------
1 | package com.limurse.onboard.internal
2 |
3 | import android.content.Context
4 | import android.graphics.Typeface
5 | import androidx.core.content.res.ResourcesCompat
6 |
7 | /**
8 | * Custom Font Cache Implementation.
9 | * Prevent(s) memory leaks due to Typeface objects
10 | */
11 | internal object CustomFontCache {
12 |
13 | private val TAG = LogHelper.makeLogTag(CustomFontCache::class)
14 | private val cache = hashMapOf()
15 |
16 | fun getFont(ctx: Context, path: String?, fontCallback: ResourcesCompat.FontCallback) {
17 | if (path.isNullOrEmpty()) {
18 | LogHelper.w(TAG, "Empty typeface path provided!")
19 | return
20 | }
21 |
22 | cache[path]?.let {
23 | // Cache hit! Return the typeface.
24 | fontCallback.onFontRetrieved(it)
25 | } ?: run {
26 | // Cache miss! Create the typeface and store it.
27 | val newTypeface = Typeface.createFromAsset(ctx.assets, path)
28 | cache[path] = newTypeface
29 | fontCallback.onFontRetrieved(newTypeface)
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/onboard/src/main/java/com/limurse/onboard/internal/LayoutUtil.kt:
--------------------------------------------------------------------------------
1 | package com.limurse.onboard.internal
2 |
3 | import android.content.Context
4 | import android.os.Build
5 | import android.view.View
6 |
7 | /**
8 | * Util object for interacting with Layouts
9 | */
10 | internal object LayoutUtil {
11 |
12 | @JvmStatic
13 | fun isRtl(ctx: Context): Boolean {
14 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 &&
15 | ctx.resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/onboard/src/main/java/com/limurse/onboard/internal/LogHelper.kt:
--------------------------------------------------------------------------------
1 | package com.limurse.onboard.internal
2 |
3 | import android.util.Log
4 | import kotlin.reflect.KClass
5 |
6 | private const val LOG_PREFIX = "Log: "
7 | private const val LOG_PREFIX_LENGTH = LOG_PREFIX.length
8 | private const val MAX_LOG_TAG_LENGTH = 23
9 |
10 | /**
11 | * Helper object to interact with the Android [Log] class.
12 | */
13 | internal object LogHelper {
14 |
15 | /**
16 | * Creates a tag for the logs from a [Class]
17 | * Don't use this when obfuscating class names!
18 | */
19 | @JvmStatic
20 | fun makeLogTag(cls: Class<*>) =
21 | LOG_PREFIX +
22 | cutTagLength(cls.simpleName, MAX_LOG_TAG_LENGTH - LOG_PREFIX_LENGTH)
23 |
24 | /**
25 | * Creates a tag for the logs from a [KClass]
26 | * Don't use this when obfuscating class names!
27 | */
28 | fun makeLogTag(cls: KClass<*>) =
29 | LOG_PREFIX +
30 | cutTagLength(cls.simpleName ?: "", MAX_LOG_TAG_LENGTH - LOG_PREFIX_LENGTH)
31 |
32 | private fun cutTagLength(tag: String, length: Int): String {
33 | return if (tag.length > length) {
34 | tag.substring(0, length - 1)
35 | } else {
36 | tag
37 | }
38 | }
39 |
40 | @JvmStatic
41 | fun d(tag: String, message: String) = Log.d(tag, message)
42 |
43 | @JvmStatic
44 | fun v(tag: String, message: String) = Log.v(tag, message)
45 |
46 | @JvmStatic
47 | fun i(tag: String, message: String) = Log.i(tag, message)
48 |
49 | @JvmOverloads
50 | @JvmStatic
51 | fun w(tag: String, message: String, throwable: Throwable? = null) {
52 | Log.w(tag, message, throwable)
53 | }
54 |
55 | @JvmOverloads
56 | @JvmStatic
57 | fun e(tag: String, message: String, throwable: Throwable? = null) {
58 | Log.e(tag, message, throwable)
59 | }
60 |
61 | @JvmOverloads
62 | @JvmStatic
63 | fun wtf(tag: String, message: String, throwable: Throwable? = null) {
64 | Log.wtf(tag, message, throwable)
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/onboard/src/main/java/com/limurse/onboard/internal/OnboardViewPager.kt:
--------------------------------------------------------------------------------
1 | package com.limurse.onboard.internal
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Context
5 | import android.util.AttributeSet
6 | import android.view.MotionEvent
7 | import android.view.animation.Interpolator
8 | import androidx.viewpager.widget.ViewPager
9 | import com.limurse.onboard.OnboardBase
10 | import com.limurse.onboard.OnboardPageTransformerType
11 | import com.limurse.onboard.OnboardViewPagerListener
12 | import com.limurse.onboard.internal.viewpager.ViewPagerTransformer
13 | import kotlin.math.max
14 |
15 | /**
16 | * Class that controls the [ViewPager] of Onboard.
17 | * This is responsible of handling of paging, managing touch and dispatching events.
18 | *
19 | * @property isFullPagingEnabled Enable or disable swiping at all.
20 | * @property isPermissionSlide If the current slide has permissions.
21 | * @property onNextPageRequestedListener Listener for Next Page events.
22 | */
23 | internal class OnboardViewPager(context: Context, attrs: AttributeSet) : ViewPager(context, attrs) {
24 |
25 | var isFullPagingEnabled = true
26 | var isPermissionSlide = false
27 | var onNextPageRequestedListener: OnboardViewPagerListener? = null
28 |
29 | private var currentTouchDownX: Float = 0.toFloat()
30 | private var currentTouchDownY: Float = 0.toFloat()
31 | private var illegallyRequestedNextPageLastCalled: Long = 0
32 | private var customScroller: ScrollerCustomDuration? = null
33 | private var pageChangeListener: OnPageChangeListener? = null
34 |
35 | init {
36 | // Override the Scroller instance with our own class so we can change the duration
37 | try {
38 | val scroller = ViewPager::class.java.getDeclaredField("mScroller")
39 | scroller.isAccessible = true
40 |
41 | val interpolator = ViewPager::class.java.getDeclaredField("sInterpolator")
42 | interpolator.isAccessible = true
43 |
44 | customScroller = ScrollerCustomDuration(context, interpolator.get(null) as Interpolator)
45 | scroller.set(this, customScroller)
46 | } catch (e: NoSuchFieldException) {
47 | e.printStackTrace()
48 | }
49 | }
50 |
51 | internal fun addOnPageChangeListener(listener: OnboardBase.OnPageChangeListener) {
52 | super.addOnPageChangeListener(listener)
53 | this.pageChangeListener = listener
54 | }
55 |
56 | fun goToNextSlide() {
57 | currentItem += if (!LayoutUtil.isRtl(context)) 1 else -1
58 | }
59 |
60 | fun goToPreviousSlide() {
61 | currentItem += if (!LayoutUtil.isRtl(context)) -1 else 1
62 | }
63 |
64 | internal fun reCenterCurrentSlide() {
65 | // Hacky way to force a recenter of the ViewPager to the current slide.
66 | // We perform a page back and forward to recenter the ViewPager at the current position.
67 | // This is needed as we're interrupting the user Swipe due to Permissions.
68 | // If the user denies a permission, we want to recenter the slide.
69 | val item = currentItem
70 | setCurrentItem(max(item - 1, 0), false)
71 | setCurrentItem(item, false)
72 | }
73 |
74 | fun isFirstSlide(size: Int): Boolean {
75 | return if (LayoutUtil.isRtl(context)) (currentItem - size + 1 == 0) else (currentItem == 0)
76 | }
77 |
78 | fun isLastSlide(size: Int): Boolean {
79 | return if (LayoutUtil.isRtl(context)) (currentItem == 0) else (currentItem - size + 1 == 0)
80 | }
81 |
82 | fun getCurrentSlideNumber(size: Int): Int {
83 | return if (LayoutUtil.isRtl(context)) (size - currentItem) else (currentItem + 1)
84 | }
85 |
86 | /**
87 | * Override is required to trigger [OnboardBase.OnPageChangeListener.onPageSelected] for the first page.
88 | * This is needed to correctly handle progress button display after rotation on a locked first page.
89 | */
90 | override fun setCurrentItem(currentItem: Int) {
91 | val oldItem = super.getCurrentItem()
92 | super.setCurrentItem(currentItem)
93 |
94 | // When you pass set current item to 0,
95 | // The pageChangeListener won't be called so we call it on our own
96 | if (oldItem == 0 && currentItem == 0) {
97 | pageChangeListener?.onPageSelected(0)
98 | }
99 | }
100 |
101 | /**
102 | * Set the factor by which the Scrolling duration will change.
103 | */
104 | fun setScrollDurationFactor(factor: Double) {
105 | customScroller?.scrollDurationFactor = factor
106 | }
107 |
108 | override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
109 | if (!handleTouchEvent(event)) {
110 | return false
111 | }
112 |
113 | // Calling super will allow the slider to "work" left and right.
114 | return super.onInterceptTouchEvent(event)
115 | }
116 |
117 | @SuppressLint("ClickableViewAccessibility") // performClick is called inside handleTouchEvent
118 | override fun onTouchEvent(event: MotionEvent): Boolean {
119 | if (!handleTouchEvent(event)) {
120 | return false
121 | }
122 |
123 | // Calling super will allow the slider to "work" left and right.
124 | return super.onTouchEvent(event)
125 | }
126 |
127 | /**
128 | * Checks for illegal sliding attempts.
129 | * Every time the user presses the screen, the respective coordinates are stored.
130 | * Once the user swipes/stops pressing, the new coordinates are checked against the stored ones.
131 | * Therefor [userIllegallyRequestNextPage] is called. If this call detects an illegal swipe,
132 | * the respective listener [onNextPageRequestedListener] gets called.
133 | */
134 | private fun handleTouchEvent(event: MotionEvent): Boolean {
135 | // If paging is disabled we should ignore any viewpager touch
136 | // (also, not display any error message)
137 | if (!isFullPagingEnabled) {
138 | return false
139 | }
140 |
141 | when (event.action) {
142 | MotionEvent.ACTION_DOWN -> {
143 | currentTouchDownX = event.x
144 | currentTouchDownY = event.y
145 | }
146 | else -> {
147 | if (event.action == MotionEvent.ACTION_UP) {
148 | performClick()
149 | }
150 | val canRequestNextPage = onNextPageRequestedListener?.onCanRequestNextPage() ?: true
151 |
152 | // If user can't request the page, we shortcircuit the ACTION_MOVE logic here.
153 | // We need to return false if we detect that the user swipes forward,
154 | // and also call onIllegallyRequestedNextPage if the threshold was too high
155 | // (so the user can be informed).
156 | if (!canRequestNextPage && isSwipeForward(currentTouchDownX, event.x)) {
157 | if (userIllegallyRequestNextPage()) {
158 | onNextPageRequestedListener?.onIllegallyRequestedNextPage()
159 | }
160 | return false
161 | }
162 |
163 | // If the slide contains permissions, check for forward swipe.
164 | if (isPermissionSlide && isSwipeForward(currentTouchDownX, event.x)) {
165 | onNextPageRequestedListener?.onUserRequestedPermissionsDialog()
166 | }
167 | }
168 | }
169 | return isFullPagingEnabled
170 | }
171 |
172 | /**
173 | * Util function to check if the user swiped forward.
174 | * The direction of forward is different in RTL mode.
175 | */
176 | private fun isSwipeForward(oldX: Float, newX: Float): Boolean {
177 | return (if (LayoutUtil.isRtl(context)) (newX > oldX) else (oldX > newX))
178 | }
179 |
180 | /**
181 | * Util function to throttle illegallyRequestedNext to max one request per second.
182 | */
183 | private fun userIllegallyRequestNextPage(): Boolean {
184 | if (System.currentTimeMillis() - illegallyRequestedNextPageLastCalled >=
185 | ON_ILLEGALLY_REQUESTED_NEXT_PAGE_MAX_INTERVAL
186 | ) {
187 | illegallyRequestedNextPageLastCalled = System.currentTimeMillis()
188 | return true
189 | }
190 |
191 | return false
192 | }
193 |
194 | fun setOnboardPageTransformer(OnboardTransformer: OnboardPageTransformerType) {
195 | setPageTransformer(true, ViewPagerTransformer(OnboardTransformer))
196 | }
197 |
198 | private companion object {
199 | private const val ON_ILLEGALLY_REQUESTED_NEXT_PAGE_MAX_INTERVAL = 1000
200 | }
201 | }
202 |
--------------------------------------------------------------------------------
/onboard/src/main/java/com/limurse/onboard/internal/PermissionWrapper.kt:
--------------------------------------------------------------------------------
1 | package com.limurse.onboard.internal
2 |
3 | import java.io.Serializable
4 |
5 | /**
6 | * A data class that represents a set of permissions that should be requested to the user.
7 | * @property permissions An Array of Permissions from the Android Framework
8 | * @property position The position in the Onboard pager when to request those permissions.
9 | * @property required Whether the permission being requested needs to be granted to move forward.
10 | */
11 | internal data class PermissionWrapper(
12 | var permissions: Array,
13 | var position: Int,
14 | var required: Boolean = true
15 | ) : Serializable {
16 |
17 | override fun equals(other: Any?): Boolean {
18 | if (this === other) return true
19 | if (javaClass != other?.javaClass) return false
20 |
21 | other as PermissionWrapper
22 |
23 | if (!permissions.contentEquals(other.permissions)) return false
24 | if (position != other.position) return false
25 | if (required != other.required) return false
26 |
27 | return true
28 | }
29 |
30 | override fun hashCode(): Int {
31 | var result = permissions.contentHashCode()
32 | result = 31 * result + position
33 | result = 31 * result + required.hashCode()
34 | return result
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/onboard/src/main/java/com/limurse/onboard/internal/ScrollerCustomDuration.kt:
--------------------------------------------------------------------------------
1 | package com.limurse.onboard.internal
2 |
3 | import android.content.Context
4 | import android.view.animation.Interpolator
5 | import android.widget.Scroller
6 |
7 | private const val DEFAULT_SCROLL_DURATION_FACTOR = 6.0
8 |
9 | /**
10 | * A [Scroller] that will allow to customize the duration of the scrolling.
11 | */
12 | internal class ScrollerCustomDuration constructor(
13 | context: Context,
14 | interpolator: Interpolator
15 | ) : Scroller(context, interpolator) {
16 |
17 | /**
18 | * Set the factor by which the duration will change
19 | */
20 | var scrollDurationFactor = DEFAULT_SCROLL_DURATION_FACTOR
21 |
22 | override fun startScroll(startX: Int, startY: Int, dx: Int, dy: Int, duration: Int) {
23 | super.startScroll(startX, startY, dx, dy, (duration * scrollDurationFactor).toInt())
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/onboard/src/main/java/com/limurse/onboard/internal/TypefaceContainer.kt:
--------------------------------------------------------------------------------
1 | package com.limurse.onboard.internal
2 |
3 | import android.graphics.Typeface
4 | import android.widget.TextView
5 | import androidx.annotation.FontRes
6 | import androidx.core.content.res.ResourcesCompat
7 |
8 | /**
9 | * Class for containing the Typefaces that can be used with Onboard.
10 | * Provide either a URL or a Resource. If you provide both, the URL will be ignored.
11 | *
12 | * @property typeFaceUrl A [String] which is an URL of a font found at in the /assets folder
13 | * @property typeFaceResource An [Int] which is a @FontRes
14 | */
15 | internal data class TypefaceContainer(
16 | var typeFaceUrl: String? = null,
17 | @FontRes var typeFaceResource: Int = 0
18 | ) {
19 |
20 | /**
21 | * Applies typeface to a given TextView object.
22 | * If there is no typeface (either URL or resource) set, this method is a no-op.
23 | *
24 | * @param textView The [TextView] where the Typeface will be applied
25 | */
26 | fun applyTo(textView: TextView?) {
27 | if (textView == null || textView.context == null) {
28 | return
29 | }
30 | if (typeFaceUrl == null && typeFaceResource == 0) {
31 | return
32 | }
33 |
34 | // Callback to font retrieval
35 | val callback = object : ResourcesCompat.FontCallback() {
36 | override fun onFontRetrievalFailed(reason: Int) {
37 | // Don't be panic, just do nothing.
38 | }
39 | override fun onFontRetrieved(typeface: Typeface) {
40 | textView.typeface = typeface
41 | }
42 | }
43 |
44 | // We give priority to the FontRes here.
45 | if (typeFaceResource != 0) {
46 | ResourcesCompat.getFont(textView.context, typeFaceResource, callback, null)
47 | } else {
48 | CustomFontCache.getFont(textView.context, typeFaceUrl, callback)
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/onboard/src/main/java/com/limurse/onboard/internal/viewpager/PagerAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.limurse.onboard.internal.viewpager
2 |
3 | import android.view.ViewGroup
4 | import androidx.fragment.app.Fragment
5 | import androidx.fragment.app.FragmentManager
6 | import androidx.fragment.app.FragmentPagerAdapter
7 |
8 | internal class PagerAdapter(
9 | fragmentManager: FragmentManager,
10 | private val fragments: MutableList
11 | ) : FragmentPagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
12 |
13 | override fun getItem(position: Int): Fragment {
14 | return fragments[position]
15 | }
16 |
17 | override fun instantiateItem(container: ViewGroup, position: Int): Any {
18 | val fragment = super.instantiateItem(container, position)
19 | fragments[position] = (fragment as Fragment)
20 | return fragment
21 | }
22 |
23 | override fun getCount() = this.fragments.size
24 | }
25 |
--------------------------------------------------------------------------------
/onboard/src/main/java/com/limurse/onboard/internal/viewpager/ViewPagerTransformer.kt:
--------------------------------------------------------------------------------
1 | package com.limurse.onboard.internal.viewpager
2 |
3 | import android.view.View
4 | import android.widget.ImageView
5 | import android.widget.TextView
6 | import androidx.viewpager.widget.ViewPager
7 | import com.limurse.onboard.OnboardPageTransformerType
8 | import com.limurse.onboard.R
9 | import kotlin.math.abs
10 | import kotlin.math.max
11 |
12 | private const val MIN_SCALE_DEPTH = 0.75f
13 | private const val MIN_SCALE_ZOOM = 0.85f
14 | private const val MIN_ALPHA_ZOOM = 0.5f
15 | private const val SCALE_FACTOR_SLIDE = 0.85f
16 | private const val MIN_ALPHA_SLIDE = 0.35f
17 |
18 | private const val FLOW_ROTATION_ANGLE = -30f
19 |
20 | internal class ViewPagerTransformer(
21 | private val transformType: OnboardPageTransformerType
22 | ) : ViewPager.PageTransformer {
23 |
24 | private var titlePF: Double = 0.0
25 | private var imagePF: Double = 0.0
26 | private var descriptionPF: Double = 0.0
27 |
28 | override fun transformPage(page: View, position: Float) {
29 | when (transformType) {
30 | OnboardPageTransformerType.Flow -> {
31 | page.rotationY = position * FLOW_ROTATION_ANGLE
32 | }
33 | OnboardPageTransformerType.SlideOver -> transformSlideOver(position, page)
34 | OnboardPageTransformerType.Depth -> transformDepth(position, page)
35 | OnboardPageTransformerType.Zoom -> transformZoom(position, page)
36 | OnboardPageTransformerType.Fade -> transformFade(position, page)
37 | is OnboardPageTransformerType.Parallax -> {
38 | titlePF = transformType.titleParallaxFactor
39 | imagePF = transformType.imageParallaxFactor
40 | descriptionPF = transformType.descriptionParallaxFactor
41 | transformParallax(position, page)
42 | }
43 | }
44 | }
45 |
46 | private fun transformParallax(position: Float, page: View) {
47 | if (position > -1 && position < 1) {
48 | try {
49 | applyParallax(page, position)
50 | } catch (e: IllegalStateException) {
51 | e.printStackTrace()
52 | }
53 | }
54 | }
55 |
56 | private fun applyParallax(page: View, position: Float) {
57 | page.findViewById(R.id.title).translationX = computeParallax(page, position, titlePF)
58 | page.findViewById(R.id.image).translationX = computeParallax(page, position, imagePF)
59 | page.findViewById(R.id.description).translationX = computeParallax(page, position, descriptionPF)
60 | }
61 |
62 | private fun computeParallax(page: View, position: Float, parallaxFactor: Double): Float {
63 | return (-position * (page.width / parallaxFactor)).toFloat()
64 | }
65 |
66 | private fun transformFade(position: Float, page: View) {
67 | if (position <= -1.0f || position >= 1.0f) {
68 | page.translationX = page.width.toFloat()
69 | page.alpha = 0.0f
70 | page.isClickable = false
71 | } else if (position == 0.0f) {
72 | page.translationX = 0.0f
73 | page.alpha = 1.0f
74 | page.isClickable = true
75 | } else {
76 | // position is between -1.0F & 0.0F OR 0.0F & 1.0F
77 | page.translationX = page.width * -position
78 | page.alpha = 1.0f - abs(position)
79 | }
80 | }
81 |
82 | private fun transformZoom(position: Float, page: View) {
83 | if (position >= -1 && position <= 1) {
84 | page.scaleXY = max(MIN_SCALE_ZOOM, 1 - abs(position))
85 | page.alpha = MIN_ALPHA_ZOOM + (page.scaleXY - MIN_SCALE_ZOOM) /
86 | (1 - MIN_SCALE_ZOOM) * (1 - MIN_ALPHA_ZOOM)
87 | val vMargin = page.height * (1 - page.scaleXY) / 2
88 | val hMargin = page.width * (1 - page.scaleXY) / 2
89 | if (position < 0) {
90 | page.translationX = hMargin - vMargin / 2
91 | } else {
92 | page.translationX = -hMargin + vMargin / 2
93 | }
94 | } else {
95 | page.transformDefaults()
96 | }
97 | }
98 |
99 | private fun transformDepth(position: Float, page: View) {
100 | if (position > 0 && position < 1) {
101 | // moving to the right
102 | page.alpha = 1 - position
103 | page.scaleXY = MIN_SCALE_DEPTH + (1 - MIN_SCALE_DEPTH) * (1 - abs(position))
104 | page.translationX = page.width * -position
105 | } else {
106 | page.transformDefaults()
107 | }
108 | }
109 |
110 | private fun transformSlideOver(position: Float, page: View) {
111 | if (position < 0 && position > -1) {
112 | // this is the page to the left
113 | page.scaleXY = abs(abs(position) - 1) * (1.0f - SCALE_FACTOR_SLIDE) + SCALE_FACTOR_SLIDE
114 | page.alpha = max(MIN_ALPHA_SLIDE, 1 - abs(position))
115 | val pageWidth = page.width
116 | val translateValue = position * -pageWidth
117 | if (translateValue > -pageWidth) {
118 | page.translationX = translateValue
119 | } else {
120 | page.translationX = 0f
121 | }
122 | } else {
123 | page.transformDefaults()
124 | }
125 | }
126 | }
127 |
128 | private fun View.transformDefaults() {
129 | this.alpha = 1f
130 | this.scaleXY = 1f
131 | this.translationX = 0f
132 | }
133 |
134 | private var View.scaleXY: Float
135 | get() = this.scaleX
136 | set(value) {
137 | this.scaleX = value
138 | this.scaleY = value
139 | }
140 |
--------------------------------------------------------------------------------
/onboard/src/main/java/com/limurse/onboard/model/SliderPage.kt:
--------------------------------------------------------------------------------
1 | package com.limurse.onboard.model
2 |
3 | import android.os.Bundle
4 | import androidx.annotation.ColorInt
5 | import androidx.annotation.DrawableRes
6 | import androidx.annotation.FontRes
7 | import com.limurse.onboard.*
8 | import com.limurse.onboard.ARG_BG_COLOR
9 | import com.limurse.onboard.ARG_BG_DRAWABLE
10 | import com.limurse.onboard.ARG_DESC
11 | import com.limurse.onboard.ARG_DESC_COLOR
12 | import com.limurse.onboard.ARG_DESC_TYPEFACE
13 | import com.limurse.onboard.ARG_DESC_TYPEFACE_RES
14 | import com.limurse.onboard.ARG_DRAWABLE
15 | import com.limurse.onboard.ARG_TITLE
16 | import com.limurse.onboard.ARG_TITLE_COLOR
17 | import com.limurse.onboard.ARG_TITLE_TYPEFACE
18 | import com.limurse.onboard.ARG_TITLE_TYPEFACE_RES
19 | import com.limurse.onboard.IS_LOTTIE
20 |
21 | /**
22 | * Slide Page Model.
23 | *
24 | * This data class represent a single page that can be visualized with Onboard.
25 | */
26 | data class SliderPage @JvmOverloads constructor(
27 | var title: CharSequence? = null,
28 | var description: CharSequence? = null,
29 | var resourceId: Int = 0,
30 | @ColorInt var backgroundColor: Int = 0,
31 | @ColorInt var titleColor: Int = 0,
32 | @ColorInt var descriptionColor: Int = 0,
33 | @FontRes var titleTypefaceFontRes: Int = 0,
34 | @FontRes var descriptionTypefaceFontRes: Int = 0,
35 | var titleTypeface: String? = null,
36 | var descriptionTypeface: String? = null,
37 | @DrawableRes var backgroundDrawable: Int = 0,
38 | var isLottie: Boolean = false
39 | ) {
40 | val titleString: String? get() = title?.toString()
41 | val descriptionString: String? get() = description?.toString()
42 |
43 | /**
44 | * Util method to convert a [SliderPage] into an Android [Bundle].
45 | * This method will be used to pass the [SliderPage] to [OnboardBaseFragment] implementations.
46 | */
47 | fun toBundle(): Bundle {
48 | val newBundle = Bundle()
49 | newBundle.putString(ARG_TITLE, this.titleString)
50 | newBundle.putString(ARG_TITLE_TYPEFACE, this.titleTypeface)
51 | newBundle.putInt(ARG_TITLE_TYPEFACE_RES, this.titleTypefaceFontRes)
52 | newBundle.putInt(ARG_TITLE_COLOR, this.titleColor)
53 | newBundle.putString(ARG_DESC, this.descriptionString)
54 | newBundle.putString(ARG_DESC_TYPEFACE, this.descriptionTypeface)
55 | newBundle.putInt(ARG_DESC_TYPEFACE_RES, this.descriptionTypefaceFontRes)
56 | newBundle.putInt(ARG_DESC_COLOR, this.descriptionColor)
57 | newBundle.putInt(ARG_DRAWABLE, this.resourceId)
58 | newBundle.putInt(ARG_BG_COLOR, this.backgroundColor)
59 | newBundle.putInt(ARG_BG_DRAWABLE, this.backgroundDrawable)
60 | newBundle.putBoolean(IS_LOTTIE, this.isLottie)
61 | return newBundle
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/onboard/src/main/java/com/limurse/onboard/model/SliderPagerBuilder.kt:
--------------------------------------------------------------------------------
1 | package com.limurse.onboard.model
2 |
3 | import androidx.annotation.ColorInt
4 | import androidx.annotation.DrawableRes
5 | import androidx.annotation.FontRes
6 |
7 | /**
8 | * A builder to help creating [SliderPage] classes.
9 | * Please use this class only in Java context. From Kotlin just create
10 | * a [SliderPage] directly.
11 | */
12 | class SliderPagerBuilder {
13 |
14 | private var title: CharSequence? = null
15 |
16 | private var description: CharSequence? = null
17 |
18 | @DrawableRes
19 | private var resourceId: Int = 0
20 |
21 | @ColorInt
22 | private var backgroundColor: Int = 0
23 |
24 | @ColorInt
25 | private var titleColor: Int = 0
26 |
27 | @ColorInt
28 | private var descriptionColor: Int = 0
29 |
30 | @FontRes
31 | private var titleTypefaceFontRes: Int = 0
32 |
33 | @FontRes
34 | private var descriptionTypefaceFontRes: Int = 0
35 |
36 | private var titleTypeface: String? = null
37 |
38 | private var descriptionTypeface: String? = null
39 |
40 | @DrawableRes
41 | private var backgroundDrawable: Int = 0
42 |
43 | fun title(title: CharSequence): SliderPagerBuilder {
44 | this.title = title
45 | return this
46 | }
47 |
48 | fun description(description: CharSequence): SliderPagerBuilder {
49 | this.description = description
50 | return this
51 | }
52 |
53 | fun resourceId(@DrawableRes resourceId: Int): SliderPagerBuilder {
54 | this.resourceId = resourceId
55 | return this
56 | }
57 |
58 | fun backgroundColor(@ColorInt backgroundColor: Int): SliderPagerBuilder {
59 | this.backgroundColor = backgroundColor
60 | return this
61 | }
62 |
63 | fun titleColor(@ColorInt titleColor: Int): SliderPagerBuilder {
64 | this.titleColor = titleColor
65 | return this
66 | }
67 |
68 | fun descriptionColor(@ColorInt descriptionColor: Int): SliderPagerBuilder {
69 | this.descriptionColor = descriptionColor
70 | return this
71 | }
72 |
73 | fun titleTypefaceFontRes(@FontRes titleTypefaceFontRes: Int): SliderPagerBuilder {
74 | this.titleTypefaceFontRes = titleTypefaceFontRes
75 | return this
76 | }
77 |
78 | fun descriptionTypefaceFontRes(@FontRes descriptionTypefaceFontRes: Int): SliderPagerBuilder {
79 | this.descriptionTypefaceFontRes = descriptionTypefaceFontRes
80 | return this
81 | }
82 |
83 | fun titleTypeface(titleTypeface: String): SliderPagerBuilder {
84 | this.titleTypeface = titleTypeface
85 | return this
86 | }
87 |
88 | fun descriptionTypeface(descriptionTypeface: String): SliderPagerBuilder {
89 | this.descriptionTypeface = descriptionTypeface
90 | return this
91 | }
92 |
93 | fun backgroundDrawable(@DrawableRes backgroundDrawable: Int): SliderPagerBuilder {
94 | this.backgroundDrawable = backgroundDrawable
95 | return this
96 | }
97 |
98 | fun build() = SliderPage(
99 | title = this.title,
100 | description = this.description,
101 | resourceId = this.resourceId,
102 | backgroundColor = this.backgroundColor,
103 | titleColor = this.titleColor,
104 | descriptionColor = this.descriptionColor,
105 | titleTypefaceFontRes = this.titleTypefaceFontRes,
106 | descriptionTypeface = this.descriptionTypeface,
107 | titleTypeface = this.titleTypeface,
108 | descriptionTypefaceFontRes = this.descriptionTypefaceFontRes,
109 | backgroundDrawable = this.backgroundDrawable
110 | )
111 | }
112 |
--------------------------------------------------------------------------------
/onboard/src/main/res/drawable-v21/ic_onboard_ripple.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | -
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/onboard/src/main/res/drawable/ic_onboard_arrow.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/onboard/src/main/res/drawable/ic_onboard_done.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/onboard/src/main/res/drawable/ic_onboard_fab_background.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
7 |
8 |
--------------------------------------------------------------------------------
/onboard/src/main/res/drawable/ic_onboard_fab_done.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/onboard/src/main/res/drawable/ic_onboard_fab_next.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/onboard/src/main/res/drawable/ic_onboard_fab_selected.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/onboard/src/main/res/drawable/ic_onboard_fab_skip.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/onboard/src/main/res/drawable/ic_onboard_indicator.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
8 |
9 |
10 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/onboard/src/main/res/drawable/ic_onboard_next.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/onboard/src/main/res/drawable/ic_onboard_ripple.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/onboard/src/main/res/drawable/ic_onboard_skip.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/onboard/src/main/res/drawable/rounded_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/onboard/src/main/res/layout-land/onboard_fragment_intro.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
23 |
24 |
31 |
32 |
38 |
39 |
47 |
48 |
49 |
50 |
61 |
62 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/onboard/src/main/res/layout/onboard_fragment_intro.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
25 |
26 |
36 |
37 |
43 |
44 |
52 |
53 |
54 |
55 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/onboard/src/main/res/layout/onboard_intro_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
21 |
22 |
30 |
31 |
39 |
40 |
49 |
50 |
60 |
61 |
71 |
72 |
80 |
81 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/onboard/src/main/res/layout/onboard_intro_layout2.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
22 |
23 |
31 |
32 |
40 |
41 |
50 |
51 |
61 |
62 |
70 |
71 |
80 |
81 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/onboard/src/main/res/values-my:
--------------------------------------------------------------------------------
1 |
2 |
3 | Melangkau
4 | Seterusnya
5 | Balik
6 | Selesai
7 | Grafik
8 |
9 |
--------------------------------------------------------------------------------
/onboard/src/main/res/values-sw600dp/dimen-sw600dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 30sp
5 | 42sp
6 | 24sp
7 | 2sp
8 |
9 | 12dp
10 | 92dp
11 | 92dp
12 |
13 | 24dp
14 | 98dp
15 | 80dp
16 |
17 | 24sp
18 | 24sp
19 | 100dp
20 | 100dp
21 |
22 |
--------------------------------------------------------------------------------
/onboard/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/onboard/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #22000000
4 | #222222
5 | #FFFFFF
6 | #FFFFFF
7 | #22000000
8 | @android:color/transparent
9 | #59000000
10 | #FFFFFF
11 | #22000000
12 | #FFFFFF
13 | #000000
14 | #1FFFFFFF
15 | #FFFFFF
16 |
17 |
--------------------------------------------------------------------------------
/onboard/src/main/res/values/dimen.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 24dp
4 |
5 | 70dp
6 | 90dp
7 |
8 | 16dp
9 | 88dp
10 | 56dp
11 | 1dp
12 |
13 | 12dp
14 | 48dp
15 | 48dp
16 |
17 | 3dp
18 | 10dp
19 | 12dp
20 |
21 | 16sp
22 | 16dp
23 | 8dp
24 | 28sp
25 | 14sp
26 | 14sp
27 | 12sp
28 | 2sp
29 |
30 |
31 |
--------------------------------------------------------------------------------
/onboard/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SKIP
4 | NEXT
5 | BACK
6 | DONE
7 | graphics
8 | Sign in
9 | Sign in
10 |
11 |
--------------------------------------------------------------------------------
/onboard/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
16 |
17 |
23 |
24 |
29 |
30 |
41 |
42 |
51 |
52 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/onboard/src/test/java/com/limurse/onboard/internal/LogHelperTest.kt:
--------------------------------------------------------------------------------
1 | package com.limurse.onboard.internal
2 |
3 | import org.junit.Assert.assertEquals
4 | import org.junit.Test
5 |
6 | class LogHelperTest {
7 |
8 | @Test
9 | fun testMakeLogTag_withJavaClass() {
10 | val logTag = LogHelper.makeLogTag(Object::class.java)
11 | assertEquals("Log: Object", logTag)
12 | }
13 |
14 | @Test
15 | fun testMakeLogTag_withKClass() {
16 | val logTag = LogHelper.makeLogTag(KotlinVersion::class)
17 | assertEquals("Log: KotlinVersion", logTag)
18 | }
19 |
20 | @Test
21 | fun testMakeLogTag_withLongName_nameIsCropped() {
22 | val logTag = LogHelper.makeLogTag(KotlinReflectionNotSupportedError::class.java)
23 | assertEquals("Log: KotlinReflectionN", logTag)
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/onboard/src/test/java/com/limurse/onboard/model/SliderPageBuilderTest.kt:
--------------------------------------------------------------------------------
1 | package com.limurse.onboard.model
2 |
3 | import android.graphics.Color
4 | import org.junit.Assert.assertEquals
5 | import org.junit.Test
6 |
7 | class SliderPageBuilderTest {
8 |
9 | @Test
10 | fun sliderPageBuilder_correctParametersAssignment() {
11 | val title = "Title"
12 | val description = "Description"
13 | val resourceId = 0x7f020000
14 | val bgDrawable = 0x7f020000
15 | val bgColor = Color.GRAY
16 | val titleColor = Color.WHITE
17 | val descColor = Color.BLACK
18 | val titleTypeface = "robotobold.ttf"
19 | val descTypeface = "OpenSans-Light.ttf"
20 | val titleTypefaceRes = 0x12345678
21 | val descTypefaceRes = 0x789abcdf
22 |
23 | val sliderPage =
24 | SliderPagerBuilder()
25 | .title(title)
26 | .description(description)
27 | .resourceId(resourceId)
28 | .backgroundColor(bgColor)
29 | .backgroundDrawable(bgDrawable)
30 | .titleColor(titleColor)
31 | .descriptionColor(descColor)
32 | .titleTypeface(titleTypeface)
33 | .descriptionTypeface(descTypeface)
34 | .titleTypefaceFontRes(titleTypefaceRes)
35 | .descriptionTypefaceFontRes(descTypefaceRes)
36 | .build()
37 |
38 | assertEquals(sliderPage.title, title)
39 | assertEquals(sliderPage.description, description)
40 | assertEquals(sliderPage.resourceId, resourceId)
41 | assertEquals(sliderPage.backgroundColor, bgColor)
42 | assertEquals(sliderPage.backgroundDrawable, bgDrawable)
43 | assertEquals(sliderPage.titleColor, titleColor)
44 | assertEquals(sliderPage.descriptionColor, descColor)
45 | assertEquals(sliderPage.titleTypeface, titleTypeface)
46 | assertEquals(sliderPage.descriptionTypeface, descTypeface)
47 | assertEquals(sliderPage.titleTypefaceFontRes, titleTypefaceRes)
48 | assertEquals(sliderPage.descriptionTypefaceFontRes, descTypefaceRes)
49 | }
50 |
51 | @Test
52 | fun sliderPageBuilder_multipleAssignmentOverrides() {
53 | val sliderPage =
54 | SliderPagerBuilder()
55 | .title("title")
56 | .title("title2")
57 | .build()
58 |
59 | assertEquals(sliderPage.title, "title2")
60 | }
61 |
62 | @Test
63 | fun sliderPageBuilder_valuesAreDefaulting() {
64 | val sliderPage = SliderPagerBuilder().build()
65 | assertEquals(sliderPage.title, null)
66 | assertEquals(sliderPage.description, null)
67 | assertEquals(sliderPage.resourceId, 0)
68 | assertEquals(sliderPage.backgroundColor, 0)
69 | assertEquals(sliderPage.backgroundDrawable, 0)
70 | assertEquals(sliderPage.titleColor, 0)
71 | assertEquals(sliderPage.descriptionColor, 0)
72 | assertEquals(sliderPage.titleTypeface, null)
73 | assertEquals(sliderPage.descriptionTypeface, null)
74 | assertEquals(sliderPage.titleTypefaceFontRes, 0)
75 | assertEquals(sliderPage.descriptionTypefaceFontRes, 0)
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/onboard/src/test/java/com/limurse/onboard/model/SliderPageTest.kt:
--------------------------------------------------------------------------------
1 | package com.limurse.onboard.model
2 |
3 | import android.graphics.Color
4 | import org.junit.Assert.assertEquals
5 | import org.junit.Test
6 |
7 | class SliderPageTest {
8 |
9 | @Test
10 | fun sliderPage_correctParametersAreAssigned() {
11 | val title = "Title"
12 | val description = "Description"
13 | val resourceId = 0x7f020000
14 | val bgColor = Color.GRAY
15 | val titleColor = Color.WHITE
16 | val descColor = Color.BLACK
17 | val titleTypeface = "robotobold.ttf"
18 | val descTypeface = "OpenSans-Light.ttf"
19 | val titleTypefaceRes = 0x12345678
20 | val descTypefaceRes = 0x789abcdf
21 |
22 | val sliderPage = SliderPage(
23 | title = title,
24 | description = description,
25 | resourceId = resourceId,
26 | backgroundColor = bgColor,
27 | titleColor = titleColor,
28 | descriptionColor = descColor,
29 | titleTypeface = titleTypeface,
30 | titleTypefaceFontRes = titleTypefaceRes,
31 | descriptionTypeface = descTypeface,
32 | descriptionTypefaceFontRes = descTypefaceRes
33 | )
34 |
35 | assertEquals(sliderPage.title, title)
36 | assertEquals(sliderPage.description, description)
37 | assertEquals(sliderPage.resourceId, resourceId)
38 | assertEquals(sliderPage.backgroundColor, bgColor)
39 | assertEquals(sliderPage.titleColor, titleColor)
40 | assertEquals(sliderPage.descriptionColor, descColor)
41 | assertEquals(sliderPage.titleTypeface, titleTypeface)
42 | assertEquals(sliderPage.descriptionTypeface, descTypeface)
43 | assertEquals(sliderPage.titleTypefaceFontRes, titleTypefaceRes)
44 | assertEquals(sliderPage.descriptionTypefaceFontRes, descTypefaceRes)
45 | }
46 |
47 | @Test
48 | fun sliderPage_valuesAreDefaulting() {
49 | val sliderPage = SliderPage()
50 |
51 | assertEquals(sliderPage.title, null)
52 | assertEquals(sliderPage.description, null)
53 | assertEquals(sliderPage.resourceId, 0)
54 | assertEquals(sliderPage.backgroundColor, 0)
55 | assertEquals(sliderPage.titleColor, 0)
56 | assertEquals(sliderPage.descriptionColor, 0)
57 | assertEquals(sliderPage.titleTypeface, null)
58 | assertEquals(sliderPage.descriptionTypeface, null)
59 | assertEquals(sliderPage.titleTypefaceFontRes, 0)
60 | assertEquals(sliderPage.descriptionTypefaceFontRes, 0)
61 | }
62 |
63 | @Test
64 | fun sliderPage_titleString_worksAfterReassignment() {
65 | val title1: CharSequence = "title1"
66 | val title2: CharSequence = "title2"
67 |
68 | val sliderPage = SliderPage(title = title1)
69 | assertEquals(title1, sliderPage.titleString)
70 | sliderPage.title = title2
71 | assertEquals(title2, sliderPage.titleString)
72 | }
73 |
74 | @Test
75 | fun sliderPage_titleDescription_worksAfterReassignment() {
76 | val desc1: CharSequence = "desc1"
77 | val desc2: CharSequence = "desc2"
78 |
79 | val sliderPage = SliderPage(description = desc1)
80 | assertEquals(desc1, sliderPage.descriptionString)
81 | sliderPage.description = desc2
82 | assertEquals(desc2, sliderPage.descriptionString)
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 | include ':onboard'
3 |
--------------------------------------------------------------------------------