├── .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 | GitHub last commit 8 | 9 | GitHub issues 11 | 12 | GitHub pull requests 14 |

15 | 16 |

17 | Features • 18 | Contribution 19 |

20 | 21 | [![Screenshot-2021-05-26-23-40-20-876-com-limurse-onboarding.jpg](https://i.postimg.cc/3wK25pJJ/Screenshot-2021-05-26-23-40-20-876-com-limurse-onboarding.jpg)](https://postimg.cc/zycyTyg9) 22 | [![ezgif-com-gif-maker-1.gif](https://i.postimg.cc/yxqFGGD2/ezgif-com-gif-maker-1.gif)](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 |