Make a cool intro for your Android app.

Overview

AppIntro

Join the chat at https://kotlinlang.slack.com Pre Merge Checks Android Arsenal Awesome Kotlin Badge

AppIntro is an Android Library that helps you build a cool carousel intro for your App. AppIntro has support for requesting permissions and helps you create a great onboarding experience in just a couple of minutes.

appintro icon appintro sample

Getting Started 👣

AppIntro is distributed through JitPack.

Adding a dependency

To use it you need to add the following gradle dependency to your build.gradle file of the module where you want to use AppIntro (NOT the root file).

repositories {
    maven { url "https://jitpack.io" }
}
dependencies {
    // AndroidX Capable version
    implementation 'com.github.AppIntro:AppIntro:6.1.0'
    
    // *** OR ***
    
    // Latest version compatible with the old Support Library
    implementation 'com.github.AppIntro:AppIntro:4.2.3'
}

Please note that since AppIntro 5.x, the library supports Android X. If you haven't migrated yet, you probably want to use a previous version of the library that uses the old Support Library packages (or try Jetifier Reverse mode).

Basic usage

To use AppIntro, you simply have to create a new Activity that extends AppIntro like the following:

class MyCustomAppIntro : AppIntro() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // Make sure you don't call setContentView!

        // Call addSlide passing your Fragments.
        // You can use AppIntroFragment to use a pre-built fragment
        addSlide(AppIntroFragment.newInstance(
                title = "Welcome...",
                description = "This is the first slide of the example"
        ))
        addSlide(AppIntroFragment.newInstance(
                title = "...Let's get started!",
                description = "This is the last slide, I won't annoy you more :)"
        ))
    }

    override fun onSkipPressed(currentFragment: Fragment?) {
        super.onSkipPressed(currentFragment)
        // Decide what to do when the user clicks on "Skip"
        finish()
    }

    override fun onDonePressed(currentFragment: Fragment?) {
        super.onDonePressed(currentFragment)
        // Decide what to do when the user clicks on "Done"
        finish()
    }
}

Please note that you must NOT call setContentView. The AppIntro superclass is taking care of it for you.

Finally, declare the activity in your Manifest like so:

<activity android:name="com.example.MyCustomAppIntro"
    android:label="My Custom AppIntro" />

We suggest to don't declare MyCustomAppIntro as your first Activity unless you want the intro to launch every time your app starts. Ideally you should show the AppIntro activity only once to the user, and you should hide it once completed (you can use a flag in the SharedPreferences).

Migrating 🚗

If you're migrating from AppIntro v5.x to v6.x, please expect multiple breaking changes. You can find documentation on how to update your code on this other migration guide.

Features 🧰

Don't forget to check the changelog to have a look at all the changes in the latest version of AppIntro.

  • API >= 14 compatible.
  • 100% Kotlin Library.
  • AndroidX Compatible.
  • Support for runtime permissions.
  • Dependent only on AndroidX AppCompat/Annotations, ConstraintLayout and Kotlin JDK.
  • Full RTL support.

Creating Slides 👩‍🎨

The entry point to add a new slide is the addSlide(fragment: Fragment) function on the AppIntro class. You can easily use it to add a new Fragment to the carousel.

The library comes with several util classes to help you create your Slide with just a couple lines:

AppIntroFragment

You can use the AppIntroFragment if you just want to customize title, description, image and colors. That's the suggested approach if you want to create a quick intro:

addSlide(AppIntroFragment.newInstance(
    title = "The title of your slide",
    description = "A description that will be shown on the bottom",
    imageDrawable = R.drawable.the_central_icon,
    backgroundDrawable = R.drawable.the_background_image,
    titleColor = Color.YELLOW,
    descriptionColor = Color.RED,
    backgroundColor = Color.BLUE,
    titleTypefaceFontRes = R.font.opensans_regular,
    descriptionTypefaceFontRes = R.font.opensans_regular,
))

All the parameters are optional, so you're free to customize your slide as you wish.

If you need to programmatically create several slides you can also use the SliderPage class. This class can be passed to AppIntroFragment.newInstance(sliderPage: SliderPage) that will create a new slide starting from that instance.

AppIntroCustomLayoutFragment

If you need further control on the customization of your slide, you can use the AppIntroCustomLayoutFragment. This will allow you pass your custom Layout Resource file:

AppIntroCustomLayoutFragment.newInstance(R.layout.intro_custom_layout1)

This allows you to achieve complex layout and include your custom logic in the Intro (see also Slide Policy):

appintro custom-layout

Configure 🎨

AppIntro offers several configuration option to help you customize your onboarding experience.

Slide Transformer

AppIntro comes with a set of Slide Transformer that you can use out of the box to animate your Slide transition.

Slide Transformers Slide Transformers
Fade
fade
Zoom
zoom
Flow
flow
Slide Over
slideover
Depth
depth
Parallax
parallax

You can simply call setTransformer() and pass one of the subclass of the sealed class AppIntroPageTransformerType:

setTransformer(AppIntroPageTransformerType.Fade)
setTransformer(AppIntroPageTransformerType.Zoom)
setTransformer(AppIntroPageTransformerType.Flow)
setTransformer(AppIntroPageTransformerType.SlideOver)
setTransformer(AppIntroPageTransformerType.Depth)

// You can customize your parallax parameters in the constructors. 
setTransformer(AppIntroPageTransformerType.Parallax(
                titleParallaxFactor = 1.0,
                imageParallaxFactor = -1.0,
                descriptionParallaxFactor = 2.0
))

Custom Slide Transformer

You can also provide your custom Slide Transformer (implementing the ViewPager.PageTransformer interface) with:

setCustomTransformer(ViewPager.PageTransformer)

Color Transition

appintro sample

AppIntro offers the possibility to animate the color transition between two slides background. This feature is disabled by default, and you need to enable it on your AppIntro with:

isColorTransitionsEnabled = true

Once you enable it, the color will be animated between slides with a gradient. Make sure you provide a backgroundColor parameter in your slides.

If you're providing custom Fragments, you can let them support the color transition by implementing the SlideBackgroundColorHolder interface.

Multiple Windows Layout

AppIntro is shipped with two top-level layouts that you can use. The default layout (AppIntro) has textual buttons, while the alternative layout has buttons with icons.

To change the Window layout, you can simply change your superclass to AppIntro2. The methods to add and customize the AppIntro are unchanged.

class MyCustomAppIntro : AppIntro2() {
    // Same code as displayed in the `Basic Usage` section of this README
}
Page AppIntro AppIntro2
standard page layout1-start layout2-start
last page layout1-end layout2-end

Indicators

AppIntro supports two indicators out of the box to show the progress of the Intro experience to the user:

  • DotIndicatorController represented with a list of Dot (the default)
  • ProgressIndicatorController represented with a progress bar.
DotIndicator ProgressIndicator
dotted indicator progress indicator

Moreover, you can supply your own indicator by providing an implementation of the IndicatorController interface.

You can customize the indicator with the following API on the AppIntro class:

// Toggle Indicator Visibility                
isIndicatorEnabled = true

// Change Indicator Color 
setIndicatorColor(
    selectedIndicatorColor = getColor(R.color.red),
    unselectedIndicatorColor = getColor(R.color.blue)
)

// Switch from Dotted Indicator to Progress Indicator
setProgressIndicator()

// Supply your custom `IndicatorController` implementation
indicatorController = MyCustomIndicator(/* initialize me */)

If you don't specify any customization, a DotIndicatorController will be shown.

Vibration

AppIntro supports providing haptic vibration feedback on button clicks. Please note that you need to specify the Vibration permission in your app Manifest (the library is not doing it). If you forget to specify the permission, the app will experience a crash.

<uses-permission android:name="android.permission.VIBRATE" />

You can enable and customize the vibration with:

// Enable vibration and set duration in ms
isVibrate = true
vibrateDuration = 50L

Wizard Mode

appintro wizard1 appintro wizard2

AppIntro supports a wizards mode where the Skip button will be replaced with the back arrow. This comes handy if you're presenting a Wizard to your user with a set of skip they need to do, and they might frequently go back and forth.

You can enable it with:

isWizardMode = true

Immersive Mode

appintro immersive1 appintro immersive2

If you want to display your Intro with a fullscreen experience, you can enable the Immersive mode. This will hide both the Status Bar and the Navigation bar and the user will have to scroll from the top of the screen to show them again.

This allows you to have more space for your Intro content and graphics.

You can enable it with:

setImmersiveMode()

System Back button

You can lock the System Back button if you don't want your user to go back from intro. This could be useful if you need to request permission and the Intro experience is not optional.

If this is the case, please set to true the following flag:

isSystemBackButtonLocked = true

System UI (Status Bar and Navigation Bar)

appintro system-ui

You can customize the Status Bar, and the Navigation Bar visibility & color with the following methods:

// Hide/Show the status Bar
showStatusBar(true)
// Control the status bar color
setStatusBarColor(Color.GREEN)
setStatusBarColorRes(R.color.green)

// Control the navigation bar color
setNavBarColor(Color.RED)
setNavBarColorRes(R.color.red)

Permission 🔒

appintro permissions

AppIntro simplifies the process of requesting runtime permissions to your user. You can integrate one or more permission request inside a slide with the askForPermissions method inside your activity.

Please note that:

  • slideNumber is in a One-based numbering (it starts from 1)
  • You can specify more than one permission if needed
  • You can specify if the permission is required. If so, users can't proceed if he denies the permission.
// Ask for required CAMERA permission on the second slide. 
askForPermissions(
    permissions = arrayOf(Manifest.permission.CAMERA),
    slideNumber = 2, 
    required = true)

// Ask for both optional ACCESS_FINE_LOCATION and WRITE_EXTERNAL_STORAGE
// permission on the third slide.
askForPermissions(
    permissions = arrayOf(
        Manifest.permission.ACCESS_FINE_LOCATION,
        Manifest.permission.WRITE_EXTERNAL_STORAGE
    ),
    slideNumber = 3, 
    required = false)

Should you need further control on the permission request, you can override those two methods on the AppIntro class:

override fun onUserDeniedPermission(permissionName: String) {
    // User pressed "Deny" on the permission dialog
}
override fun onUserDisabledPermission(permissionName: String) {
    // User pressed "Deny" + "Don't ask again" on the permission dialog
}

Slide Policy

If you want to restrict navigation between your slides (i.e. the user has to toggle a checkbox in order to continue), the SlidePolicy feature might help you.

All you have to do is implement SlidePolicy in your slides.

This interface contains the isPolicyRespected property and the onUserIllegallyRequestedNextPage method that you must implement with your custom logic

class MyFragment : Fragment(), SlidePolicy {
    
    // If user should be allowed to leave this slide
    override val isPolicyRespected: Boolean
        get() = false // Your custom logic here.

    override fun onUserIllegallyRequestedNextPage() {
        // User illegally requested next slide.
        // Show a toast or an informative message to the user.
    }
}

You can find a full working example of SlidePolicy in the example app - CustomSlidePolicyFragment.kt

Example App 💡

AppIntro comes with a sample app full of examples and use case that you can use as inspiration for your project. You can find it inside the /example folder.

You can get a debug APK of the sample app from the Pre Merge Github Actions job as an output artifact here.

appintro sample app

Translating 🌍

Do you want to help AppIntro becoming international 🌍 ? We are more than happy! AppIntro currently supports the following languages.

To add a new translation just add a pull request with a new strings.xml file inside a values-xx folder (where xx is a two-letter ISO 639-1 language code).

In order to provide the translation, your file needs to contain the following strings:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
    <string name="app_intro_skip_button">[Translation for SKIP]</string>
    <string name="app_intro_next_button">[Translation for NEXT]</string>
    <string name="app_intro_back_button">[Translation for BACK]</string>
    <string name="app_intro_done_button">[Translation for DONE]</string>
    <string name="app_intro_image_content_description">[Translation for "graphics"]</string>
</resources>

An updated version of the English version translation is available here.

If a translation in your language is already available, please check it and eventually fix it (all the strings should be listed, not just a subset).

Snapshots 📦

Development of AppIntro happens on the master branch. You can get SNAPSHOT versions directly from JitPack if needed.

repositories {
    maven { url "https://jitpack.io" }
}
dependencies {
  implementation "com.github.AppIntro:AppIntro:master-SNAPSHOT"
}

⚠️ Please note that the latest snapshot might be unstable. Use it at your own risk ⚠️

Contributing 🤝

We're offering support for AppIntro on the #appintro channel on KotlinLang Slack. Come and join the conversation over there. If you don't have access to KotlinLang Slack, you can request access here.

We're looking for contributors! Don't be shy. 👍 Feel free to open issues/pull requests to help me improve this project.

  • When reporting a new Issue, make sure to attach Screenshots, Videos or GIFs of the problem you are reporting.
  • When submitting a new PR, make sure tests are all green. Write new tests if necessary.

Acknowledgments 🌸

Maintainers

AppIntro is currently developed and maintained by the AppIntro Github Org. When submitting a new PR, please ping one of:

Libraries

AppIntro is not relying on any third party library other than those from AndroidX:

  • androidx.appcompat:appcompat
  • androidx.annotation:annotation
  • androidx.constraintlayout:constraintlayout

License 📄

    Copyright (C) 2015-2020 AppIntro Developers

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

Apps using AppIntro 📱

If you are using AppIntro in your app and would like to be listed here, please open a pull request and we will be more than happy to include you:

List of Apps using AppIntro
Comments
  • Add My App Requests -- that's you, come in here~

    Add My App Requests -- that's you, come in here~

    Would you like your app added to our application list?

    Then reply with the following [note the format]:

    App Name: Sample App Link: https://play.google.com/store/apps/details?id=paolorotolo.github.com.appintroexample

    Replace the above url with your application link!! Your Google Play listing must be publicly accessible -- please note in your comment if it is not!

    For those that want to know if I got your request; you'll find this 👍 when I see it, and then this 🎉 when it has been added by me~

    Please refrain from using 👍 or 🎉 on your own posts for this issue.

    support 
    opened by avluis 100
  • Logo Proposal

    Logo Proposal

    Hello! I find this project very interesting and I'd love to contribute to it by designing a logo. Let me know if you'd want that too and if you have anything specifically imagined for your logo, if not I'll just implement my own ideas :) looking forward to hearing from you!

    opened by newfinal100 55
  • Adding custom typeface feature & wizard development mode

    Adding custom typeface feature & wizard development mode

    This is pull request to add two new features

    1. Making a setup wizard.
    2. Adding support of custom typefaces to title, description, skip button text, done button text.

    Changelog :-

    1. Adding custom typeface feature in default AppIntro & AppIntro2
    2. Adding a static cache for Typefaces to prevent memory leaks due to Typefaces. The developers can just provide the URLs of font files in Assets folder.
    3. Adding Wizard Mode to create setup wizards instead of intros.

    Adding new methods

    //Set custom typeface to both title & description
    AppIntroFragment.newInstance("Title 1","OpenSans-Light.ttf","Description 1","OpenSans-Light.ttf",R.mipmap.ic_launcher, Color.parseColor("#3498db"));
    
    //Setting custom typeface to either title or description
    //To title only
    AppIntroFragment.newInstance("Title 1",getResources().getString(R.string.title_font),"Description 1",null,R.mipmap.ic_launcher, Color.parseColor("#3498db"));
    
    //To description
    AppIntroFragment.newInstance("Title 1",null,"Description 1",getResources().getString(R.string.title_font),R.mipmap.ic_launcher, Color.parseColor("#3498db"));
    
    //To enable Wizard mode
    setWizardMode(true); 
    
    //To set custom typeface to Skip button text.
    setSkipTextTypeface("OpenSans-Light.ttf"); // URL of font files in Assets folder.
    
    //To set custom typeface to Done button text.
    setDoneTextTypeface("OpenSans-Light.ttf"); // URL of font files in Assets folder.
    
    //show/hide backbutton on arriving at last fragment
    setBackButtonVisibilityWithDone(true); //false to hide
    
    

    Example:

    Example Image

    opened by ameykshirsagar 46
  • Unable to swipe between slides

    Unable to swipe between slides

    AppIntro Version: 4.1.0

    Device/Android Version: every device I have tried (e.g. Samsung Galaxy S5mini, LG H440N, any in emulator)

    Issue details / Repro steps / Use case background: In intro with permissions it is necessary to use e.g. android.Manifest.permission.ACCESS_FINE_LOCATION instead of Manifest.permission.ACCESS_FINE_LOCATION

    But adding android causes that I can't swipe between slides. When android is removed, i can swipe but than it can't resolve symbol ACCESS_FINE_LOCATION.

    This bad behavior is also in example project AppIntroExample on Google Play.

    bug 
    opened by romancampula 34
  • Complete UI Overhaul

    Complete UI Overhaul

    Features of this PR

    1. Rework and Resizing of Buttons to match Material Design FAB guidelines
    2. Updated Icons
    3. Added Tooltiptext attribute
    4. Removed a lot of hardcoded dimens/colors and converted into @ resource
    5. removed app_intro_fragment2 as it is basically the same file as app_intro_fragment1
    6. Merge fragment_content and fragment intro
    7. Removed unused dimens
    8. Added New Colors
    9. Modified the default dimensions of the dot indicator to look much better

    And the most important 10.Switched layouts to ConstraintLayout

    Update # 1:

    Added AppIntroStyle in styles.xml: The default style of appintro

    1. Switched every layout to full ConstraintLayout only.
    2. Removed Unused AppIntro2Fragment class
    3. Changed the setbackgroundimage method of AppIntro2 (Breaking Change)(Method still under development)
    4. Added a landscape version of appintro_fragment
    5. Major Refactoring and addition/removal of resources.
    6. Removal of more hardcoded values.
    7. The UI is smoother than before.(With less GPU overdraw)
    8. Removed overScrollAnimation as it does not look good for an Intro
    9. Removed Heading resource from values-v21 as for one single attribute (font family) we required a copy of it.(Pending replacement)

    Update 2

    1. Added a method to set background drawable to the fragment layout.
    2. Removed tooltiptext attribute and added the tooltiptextcompat to support tooltip from API level 14.
    3. Made Viewpager full-screen

    Suggestions are welcome (and required). Things currently broken:

    1. The ProgressBarIndicator in RTL mode.( Please tell me how to fix it)
    2. ~~For some reason setting the layer-list containing vector drawables causes ResourcenotfoundException on older api levels(Tested on API 19 but may apply to others). So we need to programmatically set the values. I am working on it and will update the PR when it is finished.~~ Fixed

    I will be adding support for tablets with another PR after this gets merged successfully [The values for the sizes of buttons were decided after a lot of trial and error on different devices]

    Updated

    Before screenshot_2019-02-25-22-26-08-175_com amqtech opensource appintroexample

    After screenshot_2019-03-03-17-32-58-367_com amqtech opensource appintroexample

    A Preview of the new landscape layout Landscape

    enhancement 
    opened by AnuthaDev 29
  • Would like adjustable font sizes for title and description

    Would like adjustable font sizes for title and description

    AppIntro Version: 4.2.0

    Device/Android Version: Pixel API 25

    Issue details / Repro steps / Use case background: I am trying to customize the description (and title) text so that I can change the font size.

    Your Code:

        // Code from OnCreate Method where we use your your default slide (AppIntroFragment)
    
        frag1 = AppIntroFragment.newInstance("Welcome.", "fonts/bello-pro.ttf", firstText, "fonts/bello-pro.ttf", R.drawable.intro_slide1,  Color.parseColor("#5D6CBA"));
        frag2 = AppIntroFragment.newInstance("Connect With Others.", "fonts/bello-pro.ttf", secondText, "fonts/bello-pro.ttf", R.drawable.intro_slide2, Color.parseColor("#66AC5B"));
        frag3 = AppIntroFragment.newInstance("Create and Join Events.", "fonts/bello-pro.ttf", thirdText, "fonts/bello-pro.ttf", R.drawable.intro_slide3, Color.parseColor("#CC0066"));
    
        addSlide(frag1);
        addSlide(frag2);
        addSlide(frag3);
    
        //Code from Oncreate method ends here
    
       @Override 
       public void onSlideChanged(@Nullable Fragment oldFragment, @Nullable Fragment newFragment) {
        super.onSlideChanged(oldFragment, newFragment);
    
        // Do something when the slide changes.
        descText = (TextView) findViewById(R.id.description);
        descText.setTextSize(40);
    }
    

    Stack trace / LogCat: NONE

    paste stack trace and/or log here
    

    FIRST SCREEN screen shot 2017-08-24 at 12 08 11 am

    SWITCH TO SECOND SCREEN screen shot 2017-08-24 at 1 03 28 am

    SWITCH TO THIRD SCREEN screen shot 2017-08-24 at 1 03 55 am

    SWITCH BACK TO SECOND SCREEN screen shot 2017-08-24 at 1 04 07 am

    SWITCH BACK TO FIRST SCREEN screen shot 2017-08-24 at 1 06 34 am

    NO CHANGES ARE MADE BY SWITCHING SLIDES AFTER THIS

    opened by faizanurfi 26
  • [Example App] Fragments are empty

    [Example App] Fragments are empty

    AppIntro Version: latest

    Device/Android Version: Marshmallow

    Issue details / Repro steps / Use case background: open the app

    Your Code:

    Stack trace / LogCat:

    paste stack trace and/or log here
    

    https://drive.google.com/folderview?id=0B1coFw2JziMJTkdtMHo5eTR4dG8

    bug 
    opened by adrcotfas 25
  • NPE on addView at first start of app

    NPE on addView at first start of app

    AppIntro Version: 4.1.0

    Device/Android Version: Reproduced on Nexus 6P API 24, Nexus 5 API 19 Android Studio Emulators

    Issue details / Repro steps / Use case background: I'm trying to have AppIntro show up on first start of the app. Crash occurs as soon as the app loads up. I'm using the template that's provided in this repo to determine if it is the first start of the app.

    Your Code: IntroActivity:

    //Also occurs with AppIntro2
    public class IntroActivity extends AppIntro {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_intro);
            addSlide(new IntroTextFragment());
            //This also does not fix the crash
            //addSlide(AppIntroFragment.newInstance("Welcome to Vipassana Quotes", "This app is recommended " +
            //        "for people who have done Vipassana once already.", R.drawable.ic_notifications_black_24dp, getResources().getColor(R.color.colorPrimary)));
        }
    }
    

    activity_intro.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/activity_intro"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        tools:context="com.amitavkhandelwal.vipassanaquotes.intro.IntroActivity">
    
    </RelativeLayout>
    

    IntroTextFragment:

    public class IntroTextFragment extends Fragment {
    
    
        public IntroTextFragment() {
            // Required empty public constructor
        }
    
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            // Inflate the layout for this fragment
            return inflater.inflate(R.layout.fragment_intro_text, container, false);
        }
    
    }
    

    MainActivity:

    public class MainActivity extends AppCompatActivity {
    
        public static final String TAG = MainActivity.class.getSimpleName();
        @BindView(R.id.all_quotes_recyclerview) RecyclerView allQuotesRecyclerView;
        private RealmAsyncTask transaction;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            //  Declare a new thread to do a preference check
            Thread t = new Thread(new Runnable() {
                @Override
                public void run() {
                    //  Initialize SharedPreferences
                    SharedPreferences getPrefs = PreferenceManager
                            .getDefaultSharedPreferences(getBaseContext());
    
                    //  Create a new boolean and preference and set it to true
                    boolean isFirstStart = getPrefs.getBoolean("firstStart", true);
    
                    //  If the activity has never started before...
                    if (isFirstStart) {
    
                        //  Launch app intro
                        Intent i = new Intent(MainActivity.this, IntroActivity.class);
                        startActivity(i);
    
                        //  Make a new preferences editor
                        SharedPreferences.Editor e = getPrefs.edit();
    
                        //  Edit preference to make it false because we don't want this to run again
                        e.putBoolean("firstStart", false);
    
                        //  Apply changes
                        e.apply();
                    }
                }
            });
    
            // Start the thread
            t.start();
            setContentView(R.layout.activity_main);
            ButterKnife.bind(this);
            transaction = RealmUtils.createRealmDbIfNeeded(this);
    
            QuotesAdapter allQuotesAdapter = new QuotesAdapter(RealmUtils.getAllQuotes());
            allQuotesRecyclerView.setAdapter(allQuotesAdapter);
            LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
            allQuotesRecyclerView.setLayoutManager(layoutManager);
        }
    
        @Override
        public void onStop () {
            if (transaction != null && !transaction.isCancelled()) {
                transaction.cancel();
            }
            super.onStop();
        }
    }
    

    Stack trace / LogCat:

    10-04 11:56:36.765 3045-3045/com.amitavkhandelwal.vipassanaquotes E/AndroidRuntime: FATAL EXCEPTION: main
                                                                                        Process: com.amitavkhandelwal.vipassanaquotes, PID: 3045
                                                                                        java.lang.RuntimeException: Unable to start activity ComponentInfo{com.amitavkhandelwal.vipassanaquotes/com.amitavkhandelwal.vipassanaquotes.intro.IntroActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.FrameLayout.addView(android.view.View)' on a null object reference
                                                                                            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2646)
                                                                                            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707)
                                                                                            at android.app.ActivityThread.-wrap12(ActivityThread.java)
                                                                                            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1460)
                                                                                            at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                                            at android.os.Looper.loop(Looper.java:154)
                                                                                            at android.app.ActivityThread.main(ActivityThread.java:6077)
                                                                                            at java.lang.reflect.Method.invoke(Native Method)
                                                                                            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
                                                                                            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
                                                                                         Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.FrameLayout.addView(android.view.View)' on a null object reference
                                                                                            at com.github.paolorotolo.appintro.AppIntroBase.initController(AppIntroBase.java:236)
                                                                                            at com.github.paolorotolo.appintro.AppIntroBase.onPostCreate(AppIntroBase.java:158)
                                                                                            at android.app.Instrumentation.callActivityOnPostCreate(Instrumentation.java:1199)
                                                                                            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2628)
                                                                                            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707) 
                                                                                            at android.app.ActivityThread.-wrap12(ActivityThread.java) 
                                                                                            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1460) 
                                                                                            at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                                                            at android.os.Looper.loop(Looper.java:154) 
                                                                                            at android.app.ActivityThread.main(ActivityThread.java:6077) 
                                                                                            at java.lang.reflect.Method.invoke(Native Method) 
                                                                                            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865) 
                                                                                            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755) 
    
    

    Repo that reproduces this issue: https://gitlab.com/amitav13/vipassana-quotes/tree/appintro_crash

    opened by amitav13 22
  • Update Sample App

    Update Sample App

    (Ignoring issue template since this issue is just for internal (project members) use only.) The sample app has not been updated on Google Play since May 26th. Might be a good idea to get that updated. Hopefully we can push out an app update along with the next update to the lib (perhaps when we implement RTL layouts).

    @avluis we'll need to update the sample code first, and then have @PaoloRotolo generate the APK and upload it using his key.

    opened by Sammiches327 21
  • Launching app is really slow

    Launching app is really slow

    Hi, first of all thanks foryour work, this intro looks really nice.

    I added this intro to my project and it looks really cool. However I'm using the code that you provided to Show the Intro Once and everything works just fine except that the app is really slow to star, it takes about 6 seconds to launch. If I click to show the Intro it appears almost immediatly but on the first run is really really slow.

    Do you know what could be the problem?

    Note: I tested in LG G4 and LG G3 both with Android 6.0 and Xiaomi Note 3 with Android 5.0 and all the devices have this problem.

    Thanks in advance,

    opened by BGomes17 21
  • addSlide IndexOutOfBoundsException on Android 7

    addSlide IndexOutOfBoundsException on Android 7

    AppIntro Version: 5.1.0

    Device/Android Version: Huawei P9 Plus / Android 7.0

    Issue details / Repro steps / Use case background: The tutorial slides load sucessfully and the first video is played but when I want to go to the next video it crashes with the exception shown below. This only happens on Android 7. On a Samsung S10 with Android 10 it works fine.

    Your Code:

    public class TutorialActivity extends AppIntro {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            // Note here that we DO NOT use setContentView();
    
            boolean full = getIntent().getBooleanExtra("full", true);
    
            // Add your slide fragments here.
            // AppIntro will automatically generate the dots indicator and buttons.
            if (full) {
                addSlide(TutorialFragment.newInstance("1. Keyboard", R.raw.keyboard));
                addSlide(TutorialFragment.newInstance("2. Self-Reports", R.raw.self_report));
                addSlide(TutorialFragment.newInstance("2.1. Example 1", R.raw.example1));
                addSlide(TutorialFragment.newInstance("2.2. Example 2", R.raw.example2));
                addSlide(TutorialFragment.newInstance("2.3. Example 3", R.raw.example3));
                addSlide(TutorialFragment.newInstance("2.4. Example 4", R.raw.example4));
                addSlide(TutorialFragment.newInstance("3. App", R.raw.app));
            } else {
                addSlide(TutorialFragment.newInstance("Definition", R.raw.self_report));
                addSlide(TutorialFragment.newInstance("Example 1", R.raw.example1));
                addSlide(TutorialFragment.newInstance("Example 2", R.raw.example2));
                addSlide(TutorialFragment.newInstance("Example 3", R.raw.example3));
                addSlide(TutorialFragment.newInstance("Example 4", R.raw.example4));
            }
    
            // Set Background color
            setBarColor(Color.parseColor("#0069B4"));
            setSeparatorColor(Color.parseColor("#0069B4"));
    
            // Show Skip button
            showSkipButton(true);
    
            // Show how far progress is
            setProgressButtonEnabled(true);
    
            // Don't Turn vibration on
            setVibrate(false);
    
            // Set animation for changing fragment
            setZoomAnimation();
        }
    
        @Override
        public void onSkipPressed(Fragment currentFragment) {
            super.onSkipPressed(currentFragment);
    
            finishTutorial();
        }
    
        @Override
        public void onDonePressed(Fragment currentFragment) {
            super.onDonePressed(currentFragment);
    
            finishTutorial();
        }
    
        @Override
        public void onSlideChanged(@Nullable Fragment oldFragment, @Nullable Fragment newFragment) {
            super.onSlideChanged(oldFragment, newFragment);
    
            if(newFragment instanceof TutorialFragment) {
                ((TutorialFragment) newFragment).startVideo();
            }
            if(oldFragment instanceof TutorialFragment) {
                ((TutorialFragment) oldFragment).stopVideo();
            }
        }
    
        /**
         * Closes the Tutorial activity
         *
         */
        private void finishTutorial() {
            finish();
        }
    }
    
    public class TutorialFragment extends Fragment {
    
        private static final String EXTRA_TITLE = "extra_title";
        public static final String EXTRA_VIDEO = "extra_video";
    
        private VideoView mVideoView;
    
        public static final TutorialFragment newInstance(String title, int videoId) {
            // Load tutorial data
            TutorialFragment f = new TutorialFragment();
            Bundle bd = new Bundle(2);
            bd.putString(EXTRA_TITLE, title);
            bd.putInt(EXTRA_VIDEO, videoId);
            f.setArguments(bd);
            return f;
        }
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_tutorial, container, false);
    
            // Set tutorial title
            TextView title = rootView.findViewById(R.id.tutorial_title);
            title.setText(getArguments().getString(EXTRA_TITLE));
    
            // Set tutorial video
            mVideoView = rootView.findViewById(R.id.tutorial_video);
    
            // Load video file
            String path = "android.resource://" + getContext().getPackageName() + "/" + getArguments().getInt(EXTRA_VIDEO);
            Uri uri= Uri.parse(path);
    
            // Set video parameters
            mVideoView.setMediaController(null);
            mVideoView.setVideoURI(uri);
            mVideoView.requestFocus();
    
            return rootView;
        }
    
        /**
         * Start running the video
         *
         */
        public void startVideo() {
            mVideoView.start();
            mVideoView.seekTo(0);
        }
    
        /**
         * Stops running the video
         *
         */
        public void stopVideo() {
            mVideoView.stopPlayback();
        }
    }
    

    Stack trace / LogCat:

    java.lang.IndexOutOfBoundsException: Index: 2, Size: 2
    
    --------- Stack trace ---------
    
        java.util.ArrayList.get(ArrayList.java:411)
        androidx.viewpager.widget.ViewPager.getChildDrawingOrder(ViewPager.java:804)
        android.view.View.populateAccessibilityNodeInfoDrawingOrderInParent(View.java:7010)
        android.view.View.onInitializeAccessibilityNodeInfoInternal(View.java:6969)
        android.view.View.onInitializeAccessibilityNodeInfo(View.java:6584)
        android.view.View.createAccessibilityNodeInfoInternal(View.java:6543)
        android.view.View.createAccessibilityNodeInfo(View.java:6528)
        android.view.accessibility.AccessibilityRecord.setSource(AccessibilityRecord.java:145)
        android.view.accessibility.AccessibilityRecord.setSource(AccessibilityRecord.java:119)
        android.view.View.onInitializeAccessibilityEventInternal(View.java:6480)
        android.view.View.onInitializeAccessibilityEvent(View.java:6468)
        android.view.View.sendAccessibilityEventUncheckedInternal(View.java:6329)
        android.view.View.sendAccessibilityEventUnchecked(View.java:6314)
        android.view.View$SendViewStateChangedAccessibilityEvent.run(View.java:23705)
        android.view.View$SendViewStateChangedAccessibilityEvent.runOrPost(View.java:23738)
        android.view.View.notifyViewAccessibilityStateChangedIfNeeded(View.java:9476)
        android.view.View.onFocusChanged(View.java:6197)
        android.view.View.clearFocusInternal(View.java:6101)
        android.view.View.unFocus(View.java:6134)
        android.view.ViewGroup.unFocus(ViewGroup.java:997)
        android.view.ViewGroup.unFocus(ViewGroup.java:997)
        android.view.ViewGroup.unFocus(ViewGroup.java:997)
        android.view.ViewGroup.requestChildFocus(ViewGroup.java:734)
        android.view.ViewGroup.addViewInner(ViewGroup.java:4503)
        android.view.ViewGroup.addView(ViewGroup.java:4312)
        androidx.viewpager.widget.ViewPager.addView(ViewPager.java:1485)
        android.view.ViewGroup.addView(ViewGroup.java:4252)
        android.view.ViewGroup.addView(ViewGroup.java:4225)
        androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:326)
        androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1187)
        androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1356)
        androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1434)
        androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1497)
        androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:447)
        androidx.fragment.app.FragmentManager.executeOps(FragmentManager.java:2169)
        androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1992)
        androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1947)
        androidx.fragment.app.FragmentManager.execSingleAction(FragmentManager.java:1818)
        androidx.fragment.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:303)
        androidx.fragment.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:246)
        androidx.viewpager.widget.ViewPager.populate(ViewPager.java:1244)
        androidx.viewpager.widget.ViewPager.setCurrentItemInternal(ViewPager.java:669)
        androidx.viewpager.widget.ViewPager.setCurrentItemInternal(ViewPager.java:631)
        androidx.viewpager.widget.ViewPager.setCurrentItem(ViewPager.java:612)
        com.github.paolorotolo.appintro.AppIntroViewPager.setCurrentItem(AppIntroViewPager.java:84)
        com.github.paolorotolo.appintro.AppIntroViewPager.goToNextSlide(AppIntroViewPager.java:47)
        com.github.paolorotolo.appintro.AppIntroBase.changeSlide(AppIntroBase.java:965)
        com.github.paolorotolo.appintro.AppIntroBase.access$300(AppIntroBase.java:41)
        com.github.paolorotolo.appintro.AppIntroBase$NextButtonOnClickListener.onClick(AppIntroBase.java:1059)
        android.view.View.performClick(View.java:5646)
        android.view.View$PerformClick.run(View.java:22459)
        android.os.Handler.handleCallback(Handler.java:761)
        android.os.Handler.dispatchMessage(Handler.java:98)
        android.os.Looper.loop(Looper.java:156)
        android.app.ActivityThread.main(ActivityThread.java:6523)
        java.lang.reflect.Method.invoke(Native Method)
        com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:942)
        com.android.internal.os.ZygoteInit.main(ZygoteInit.java:832)
    
    bug incomplete 
    opened by Eichhof 19
  • IndexOutOfBoundsException from time to time

    IndexOutOfBoundsException from time to time

    🐛 Describe the bug

    We use AppIntro in our app (https://github.com/bitfireAT/davx5). The slides are created dynamically in onCreate(). Which slides are shown depends on various conditions.

    ⚠️ Current behavior

    Everything is working fine, but there are mysterious app crashes in Google Play that don't go away. Stack trace:

    java.lang.IndexOutOfBoundsException: 
      at java.util.ArrayList.get (ArrayList.java:437)
      at com.github.appintro.internal.viewpager.PagerAdapter.getItem (PagerAdapter.kt:14)
      at com.github.appintro.AppIntroBase$onPostCreate$1.run (AppIntroBase.kt:458)
      at android.os.Handler.handleCallback (Handler.java:883)
      at android.os.Handler.dispatchMessage (Handler.java:100)
      at android.os.Looper.loop (Looper.java:237)
      at android.app.ActivityThread.main (ActivityThread.java:8167)
      at java.lang.reflect.Method.invoke (Native Method)
      at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:496)
      at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1100)
    

    Unfortunately, I couldn't reproduce this crash until now. Do you maybe have an idea how I could do that?

    ✅ Expected behavior

    AppIntroBase shouldn't crash. If a fragment is not found in the list (for whatever reason), this should be handled gracefully.

    📱 Tech info

    • AppIntro Version: 6.2.0
    • Android OS Version: various
    opened by rfc2822 3
  • Move away from `Fragment.retainInstance`

    Move away from `Fragment.retainInstance`

    ⚠️ The problem

    We're currently using Fragment.retainInstance which is deprecated: https://github.com/AppIntro/AppIntro/blob/3a301e4021e3a81c8684defc63f06bb623afc3b5/appintro/src/main/java/com/github/appintro/AppIntroBaseFragment.kt#L72

    💡 Describe the solution you'd like

    We should instead use a ViewModel to store the state of the Fragment and move away from the onActivityCreated method as well.

    enhancement help wanted 
    opened by cortinico 0
  • Move to ViewPager2

    Move to ViewPager2

    ⚠️ Current problem

    Our library builds on top of FragmentPagerAdapter. This class is deprecated: https://developer.android.com/reference/androidx/fragment/app/FragmentPagerAdapter

    💡 Describe the solution you'd like

    We should move to ViewPager2 and eventually use FragmentStateAdapter: https://developer.android.com/reference/androidx/viewpager2/adapter/FragmentStateAdapter

    @paolorotolo has started to look into this. We'll be happy to collaborate or accept PRs that help us investigate this change.

    Please note that this change is most likely non-trivial and will probably require a breaking change.

    enhancement help wanted 
    opened by cortinico 3
  • Dependency Dashboard

    Dependency Dashboard

    This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

    This repository currently has no open or pending branches.

    Detected dependencies

    github-actions
    .github/workflows/gradle-wrapper-validation.yml
    • actions/checkout v3
    • gradle/wrapper-validation-action v1
    .github/workflows/pre-merge.yml
    • actions/checkout v3
    • actions/setup-java v3
    • actions/checkout v3
    • actions/setup-java v3
    • actions/checkout v3
    • actions/setup-java v3
    • actions/checkout v3
    • actions/setup-java v3
    • actions/checkout v3
    • actions/setup-java v3
    • actions/upload-artifact v3
    gradle
    gradle.properties
    settings.gradle.kts
    build.gradle.kts
    appintro/gradle.properties
    appintro/build.gradle.kts
    example/build.gradle.kts
    gradle/libs.versions.toml
    • androidx.annotation:annotation 1.5.0
    • androidx.appcompat:appcompat 1.5.1
    • androidx.cardview:cardview 1.0.0
    • androidx.constraintlayout:constraintlayout 2.1.4
    • androidx.recyclerview:recyclerview 1.2.1
    • junit:junit 4.13.2
    • com.android.application 7.3.1
    • org.jetbrains.kotlin.android 1.8.0
    • com.android.library 7.3.1
    • io.gitlab.arturbosch.detekt 1.22.0
    gradle-wrapper
    gradle/wrapper/gradle-wrapper.properties
    • gradle 7.6

    • [ ] Check this box to trigger a request for Renovate to run again on this repository
    opened by renovate[bot] 0
  • Fatal Exception: java.lang.RuntimeException: Unable to instantiate fragment mb.h: could not find Fragment constructor

    Fatal Exception: java.lang.RuntimeException: Unable to instantiate fragment mb.h: could not find Fragment constructor

    🐛 Describe the bug

    I'm having a crash in some users (~0.1% of them) when they open an AppIntro2 activity. See the device list because I think it is very suspicious.

    ⚠️ Current behavior

    Activity crashing sometimes

    ✅ Expected behavior

    Activity created well

    💣 Steps to reproduce

    Couldn't reproduce it

    📑 Your Code

    build.gradle implementation 'com.github.AppIntro:AppIntro:6.2.0'

    Exception stacktrace

    
    **Fatal Exception: java.lang.RuntimeException: Unable to start activity ComponentInfo{packagexxx.activities.IntroActivity}: androidx.fragment.app.Fragment$InstantiationException: Unable to instantiate fragment mb.h: could not find Fragment constructor**
           at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3298)
           at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3437)
           at android.app.ActivityThread.handleRelaunchActivityInner(ActivityThread.java:5307)
           at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:5215)
           at android.app.servertransaction.ActivityRelaunchItem.execute(ActivityRelaunchItem.java:69)
           at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
           at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
           at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2041)
           at android.os.Handler.dispatchMessage(Handler.java:107)
           at android.os.Looper.loop(Looper.java:214)
           at android.app.ActivityThread.main(ActivityThread.java:7386)
           at java.lang.reflect.Method.invoke(Method.java)
           at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:514)
           at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:980)
    
    **Caused by androidx.fragment.app.Fragment$InstantiationException: Unable to instantiate fragment mb.h: could not find Fragment constructor**
           at androidx.fragment.app.Fragment.instantiate(Fragment.java:630)
           at androidx.fragment.app.FragmentContainer.instantiate(FragmentContainer.java:57)
           at androidx.fragment.app.FragmentManager$2.instantiate(FragmentManager.java:448)
           at androidx.fragment.app.FragmentState.instantiate(FragmentState.java:81)
           at androidx.fragment.app.FragmentStateManager.<init>(FragmentStateManager.java:85)
           at androidx.fragment.app.FragmentManager.restoreSaveStateInternal(FragmentManager.java:2410)
           at androidx.fragment.app.FragmentManager.attachController(FragmentManager.java:2584)
           at androidx.fragment.app.FragmentController.attachHost(FragmentController.java:116)
           at androidx.fragment.app.FragmentActivity.lambda$init$1(FragmentActivity.java:128)
           at androidx.fragment.app.FragmentActivity.$r8$lambda$QtiQ2ZI3e38UkO1_xuJ8vE_JZj4(FragmentActivity.java)
           at androidx.fragment.app.FragmentActivity$$InternalSyntheticLambda$0$cef12c4fb802c6ea87b1fbddce076644080634cb6e3f7fb823e201a9f4f7f1ec$1.onContextAvailable(FragmentActivity.java:2)
           at androidx.activity.contextaware.ContextAwareHelper.dispatchOnContextAvailable(ContextAwareHelper.java:99)
           at androidx.activity.ComponentActivity.onCreate(ComponentActivity.java:322)
           at androidx.fragment.app.FragmentActivity.onCreate(FragmentActivity.java:249)
           **at com.github.appintro.AppIntroBase.onCreate(AppIntroBase.kt:395)
           at com.github.appintro.AppIntro2.onCreate(AppIntro2.kt:40)
           at packagexxx.activities.IntroActivity.onCreate(IntroActivity.java:21)**
           at android.app.Activity.performCreate(Activity.java:7802)
           at android.app.Activity.performCreate(Activity.java:7791)
           at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1306)
           at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3273)
           at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3437)
           at android.app.ActivityThread.handleRelaunchActivityInner(ActivityThread.java:5307)
           at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:5215)
           at android.app.servertransaction.ActivityRelaunchItem.execute(ActivityRelaunchItem.java:69)
           at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
           at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
           at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2041)
           at android.os.Handler.dispatchMessage(Handler.java:107)
           at android.os.Looper.loop(Looper.java:214)
           at android.app.ActivityThread.main(ActivityThread.java:7386)
           at java.lang.reflect.Method.invoke(Method.java)
           at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:514)
           at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:980)
    
    **Caused by java.lang.NoSuchMethodException: mb.h.<init> []**
           at java.lang.Class.getConstructor0(Class.java:2332)
           at java.lang.Class.getConstructor(Class.java:1728)
           at androidx.fragment.app.Fragment.instantiate(Fragment.java:615)
           at androidx.fragment.app.FragmentContainer.instantiate(FragmentContainer.java:57)
           at androidx.fragment.app.FragmentManager$2.instantiate(FragmentManager.java:448)
           at androidx.fragment.app.FragmentState.instantiate(FragmentState.java:81)
           at androidx.fragment.app.FragmentStateManager.<init>(FragmentStateManager.java:85)
           at androidx.fragment.app.FragmentManager.restoreSaveStateInternal(FragmentManager.java:2410)
           at androidx.fragment.app.FragmentManager.attachController(FragmentManager.java:2584)
           at androidx.fragment.app.FragmentController.attachHost(FragmentController.java:116)
           at androidx.fragment.app.FragmentActivity.lambda$init$1(FragmentActivity.java:128)
           at androidx.fragment.app.FragmentActivity.$r8$lambda$QtiQ2ZI3e38UkO1_xuJ8vE_JZj4(FragmentActivity.java)
           at androidx.fragment.app.FragmentActivity$$InternalSyntheticLambda$0$cef12c4fb802c6ea87b1fbddce076644080634cb6e3f7fb823e201a9f4f7f1ec$1.onContextAvailable(FragmentActivity.java:2)
           at androidx.activity.contextaware.ContextAwareHelper.dispatchOnContextAvailable(ContextAwareHelper.java:99)
           at androidx.activity.ComponentActivity.onCreate(ComponentActivity.java:322)
           at androidx.fragment.app.FragmentActivity.onCreate(FragmentActivity.java:249)
           **at com.github.appintro.AppIntroBase.onCreate(AppIntroBase.kt:395)
           at com.github.appintro.AppIntro2.onCreate(AppIntro2.kt:40)
           at packagexxx.activities.IntroActivity.onCreate(IntroActivity.java:21)**
           at android.app.Activity.performCreate(Activity.java:7802)
           at android.app.Activity.performCreate(Activity.java:7791)
           at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1306)
           at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3273)
           at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3437)
           at android.app.ActivityThread.handleRelaunchActivityInner(ActivityThread.java:5307)
           at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:5215)
           at android.app.servertransaction.ActivityRelaunchItem.execute(ActivityRelaunchItem.java:69)
           at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
           at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
           at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2041)
           at android.os.Handler.dispatchMessage(Handler.java:107)
           at android.os.Looper.loop(Looper.java:214)
           at android.app.ActivityThread.main(ActivityThread.java:7386)
           at java.lang.reflect.Method.invoke(Method.java)
           at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:514)
           at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:980)
    

    Java code

            Intent intent = new Intent(this, IntroActivity.class);
            startActivityForResult(intent, TUTORIALEND);
    
    ...
    ...
    
    public class IntroActivity extends AppIntro2 {
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            // Note here that we DO NOT use setContentView();
    
            setImmersiveMode();
    
            Fragment fragment1 = Intro.newInstance();
            Fragment fragment2 = Intro2.newInstance();
    
            addSlide(fragment1);
            addSlide(fragment2);
    
            setSkipButtonEnabled(true);
    
            setColorTransitionsEnabled(true);
    
            setVibrate(true);
            setVibrateDuration(70);
    
        }
    ...
    
    

    📱 Tech info

    • AppIntro Version: 6.2.0
    • Device: Nokia 2.4, Redmi 9A, Redmi 9C, ZenFone Max Shot (ZB634KL), Redmi 7A, HOT 7, C5 2019, HOT 6 Pro, TCL A3, T6, Redmi Note 8 Pro
    • Android OS Version: 8,9,10,11
    opened by marmayy 2
  • RTL layout issue after changing the app language manually

    RTL layout issue after changing the app language manually

    🐛 Describe the bug

    When the default language of the system is Persian (RTL), the intro is displayed without any problems and correctly. But when the language of the system is not Persian (e.g. English) and we change the language of the app to Persian manually, the intro is still LTR and the slide shows the beginning and the end incorrectly. If you pay attention to the screenshots, you will understand better. I have tried all the old and new methods but in all of them this problem persists. Of course, there are no problems with other activities and they are displayed correctly.

    💣 Steps to reproduce

    Adding this code in activity:

    init {
        val locale = Locale("fa", "IR")
        val configuration = Configuration()
        Locale.setDefault(locale)
        configuration.setLocale(locale)
        this.applyOverrideConfiguration(configuration)
    }
    

    This code works properly in newer versions of Android, but I does not tested it on Android N and older.

    Of course, I tried many other codes, and this was the simplest code available.

    📷 Screenshots

    This screenshot is when the language of the system itself is Persian:

    02

    But this screenshot is when the system language is English and I manually changed the app language to Persian

    01

    📱 Tech info

    • AppIntro Version: 6.2.0
    • Device: Samsung Galaxy A51 5G
    • Android OS Version: 11 R
    bug help wanted 
    opened by AlirezaIvaz 2
Releases(6.2.0)
  • 6.2.0(Jan 27, 2022)

    This is a new minor release of AppIntro. This library comes with several new features (see below) and bugfixes.

    Summary of Changes

    • We deprecated AppIntroFragment.newInstance in favor of AppIntroFragment.createInstance. This was needed in order to support passing color resources instead of color int, to tackle scenarios such as configuration changes and dark mode [#979].
    • Target SDK is now 31
    • We exposed a couple of properties/methods on the public API that were requested by the community ([#960] and [#959])
    • We added some Java examples for our Java users [#953]

    Enhancements 🎁

    • [#959] Add @JvmOverloads on goToNextSlide
    • [#960] Expose a protected property for slidesNumber
    • [#979] Fix #926: Add color resource parameters
    • [#993] Make description scrollable

    Bugfixes 🐛

    • [#934] Fix ProgressIndicatorController in RTL

    Dependency updates 📦

    • Java version to 11
    • Kotlin to 1.6.10
    • AGP to 7.0.3
    • Androidx Appcompat to 1.4.0
    • ConstraintLayout to 2.1.2

    New Contributors

    • @Fabi755 made their first contribution in https://github.com/AppIntro/AppIntro/pull/979
    • @Massi-X made their first contribution in https://github.com/AppIntro/AppIntro/pull/953
    Source code(tar.gz)
    Source code(zip)
  • 6.1.0(Feb 3, 2021)

    This is a new minor release of AppIntro. This library comes with several new features and several bugfixes.

    Summary of Changes

    • Target SDK is now 30.
    • Text visualization has been improved with Autosizing TextViews and URL autolinking.
    • AppIntro now offers better support for tablets (sw600dp).
    • Slide indicator has been improved with better color blending and it won't be shown if you have only one slide.
    • The AppIntro sample app has been completely rewritten with more examples (for Java, SlidePolicy and more).
    • 14 translations have been added or improved.

    The full changelog is available in the CHANGELOG file

    To update make sure you:

    1. Add the JitPack repository to your build file
    repositories {
        maven { url "jitpack.io" }
    }
    
    1. Bump the dependency
    dependencies {
        implementation 'com.github.AppIntro:AppIntro:6.1.0'
    }
    
    Source code(tar.gz)
    Source code(zip)
  • 6.0.0(May 4, 2020)

    This is a new major release of AppIntro. Please note that this release contains multiple new features (see below), several bugfixes, as well as multiple breaking changes. To get a deeper overview of the breaking changes, please read the migration document.

    Summary of Changes

    • The library is now 100% in Kotlin! 🎉.
    • Target SDK is now 29.
    • The UI was completely revamped and refactored.
    • You can now request permissions on AppIntro without having to lock the slide.
    • The library has now 14 more translations.

    The full changelog is available in the CHANGELOG file

    How to update

    This release contains several breaking change. Please read them all in the migration document

    1. Add the JitPack repository to your build file
    repositories {
        maven { url "https://jitpack.io" }
    }
    
    1. Add the dependency
    dependencies {
        implementation 'com.github.AppIntro:AppIntro:6.0.0'
    }
    
    Source code(tar.gz)
    Source code(zip)
    appintro-6.0.0-sources.jar(27.87 KB)
    appintro-6.0.0.aar(108.87 KB)
    appintro-6.0.0.pom.xml(1.50 KB)
  • v5.1.0(Oct 23, 2018)

    Changelog

    • Fixed issue that caused a build failure on Kotlin projects (#597);
    • Added support for Android 8.0 custom Fonts API (#590);
    • Updated Translations;
    • Miscellaneous bug fixes and performance improvements;

    How to update

    1. Add the JitPack repository to your build file Add it in your root build.gradle at the end of repositories:
    allprojects {
        repositories {
    	...
    	maven { url 'https://jitpack.io' }
        }
    }
    
    1. Add the dependency
    dependencies {
             implementation 'com.github.paolorotolo:appintro:v5.1.0'
    }
    
    Source code(tar.gz)
    Source code(zip)
  • v5.0.1(Oct 16, 2018)

    Changelog

    • Fixed incorrect behaviour when android:supportsRtl="true" was present in app's Manifest;
    • Fixed RTL support;
    • Update Translations;
    • Miscellaneous bug fixes and performance improvements;

    How to update

    1. Add the JitPack repository to your build file Add it in your root build.gradle at the end of repositories:
    allprojects {
        repositories {
    	...
    	maven { url 'https://jitpack.io' }
        }
    }
    
    1. Add the dependency
    dependencies {
             implementation 'com.github.paolorotolo:AppIntro:v5.0.1'
    }
    
    Source code(tar.gz)
    Source code(zip)
  • v5.0.0(Oct 7, 2018)

    Changelog

    • Migrate to AndroidX;
    • Target SDK 28;
    • Update Translations;
    • Miscellaneous bug fixes and performance improvements;

    How to update

    1. Add the JitPack repository to your build file Add it in your root build.gradle at the end of repositories:
    allprojects {
        repositories {
    	...
    	maven { url 'https://jitpack.io' }
        }
    }
    
    1. Add the dependency
    dependencies {
             implementation 'com.github.paolorotolo:AppIntro:v5.0.0'
    }
    
    Source code(tar.gz)
    Source code(zip)
  • v4.2.3(Feb 13, 2018)

    Changelog

    • BREAKING: MinSdkVersion raised to 14;
    • FIX: PagerIndicatorEnabled is updated only at start (#478);
    • FIX: redundant and wrong calls to onUserIllegallyRequestedNextPage;
    • New translations;

    How to update

    1. Add the JitPack repository to your build file Add it in your root build.gradle at the end of repositories:
    allprojects {
        repositories {
    	...
    	maven { url 'https://jitpack.io' }
        }
    }
    
    1. Add the dependency
    dependencies {
        compile 'com.github.apl-devs:appintro:v4.2.3'
    }
    
    Source code(tar.gz)
    Source code(zip)
  • v4.2.2(Jul 29, 2017)

    How to update

    1. Add the JitPack repository to your build file Add it in your root build.gradle at the end of repositories:
    allprojects {
        repositories {
    	...
    	maven { url 'https://jitpack.io' }
        }
    }
    
    1. Add the dependency
    dependencies {
        compile 'com.github.apl-devs:appintro:v4.2.2'
    }
    

    Changelog

    Bugfixes

    • Fix broken permission request behavior (#472)

    Thanks to all contributors who made this release possible!

    Source code(tar.gz)
    Source code(zip)
  • v4.2.1(Jul 22, 2017)

    How to update

    Time for a quick update! As per the last release, we switched from Maven to JitPack.io. Updating AppIntro is very simple.

    1. Add the JitPack repository to your build file Add it in your root build.gradle at the end of repositories:
    allprojects {
        repositories {
    	...
    	maven { url 'https://jitpack.io' }
        }
    }
    
    1. Add the dependency
    dependencies {
        compile 'com.github.apl-devs:appintro:v4.2.1'
    }
    

    Changelog

    Features

    Bugfixes

    • Fix permission request on last slide (#416)
    • Code cleanup/refactoring! (#428)
    • Fix IndexOutOfBoundsException when no slides are passed (#455)

    Thanks to all contributors who made this release possible!

    Source code(tar.gz)
    Source code(zip)
  • v4.2.0(May 26, 2017)

    How to update

    In this release we switched from Maven to JitPack.io. Updating AppIntro is even more simple.

    1. Add the JitPack repository to your build file Add it in your root build.gradle at the end of repositories:
    	allprojects {
    		repositories {
    			...
    			maven { url 'https://jitpack.io' }
    		}
    	}
    
    1. Add the dependency
    	dependencies {
    	        compile 'com.github.apl-devs:appintro:v4.2.0'
    	}
    

    Changelog

    Features

    • Add Translations (French, Indonesian, Russian, Turkish, Arabic);
    • Add RTL Support;
    • Add back button navigation;
    • Add showSeparator() method;
    • Allow users to change Bar color in AppIntro 2;
    • Refreshed Example app;
    • Dependencies update;

    Bugfixes

    • Check NPE on views (#361);
    • Fix issues with ProGuard (#337);
    • Fix Custom Typefaces issues (#318);
    • Fix page indicator when the page change listener is overridden (#316);

    Thanks to all contributors who made this release possible!

    Source code(tar.gz)
    Source code(zip)
  • v4.1.0(Sep 27, 2016)

    How to update

    Add this to your build.gradle:

    repositories {
        mavenCentral()
    }
    
    dependencies {
      compile 'com.github.paolorotolo:appintro:4.1.0'
    }
    

    Changelog:

    • Long Description Support @SandroMachado #234
    • Changes to Skip Button Visibility @RafaG #241
    • Added Wizard Mode & Custom Typeface Support @ameykshirsagar #267
    • Improve compatibility with Vector Drawables @xsorifc28 #271 & @K0bin #296
    • Add German Translations @K0bin #291
    • Add Spanish Translations @voghDev #292
    • Documentation updates @maxee #302
    Source code(tar.gz)
    Source code(zip)
  • v4.0.0(May 29, 2016)

    How to update

    Add this to your build.gradle:

    repositories {
        mavenCentral()
    }
    
    dependencies {
      compile 'com.github.paolorotolo:appintro:4.0.0'
    }
    

    Changelog:

    • Users can now override onCreate();
    • New method: setNextArrowColor() [@championswimmer];
    • Implemented basic support to restore fragments (e.g. on orientation change) [@maxee];
    • Implemented support for immersive mode [@maxee];
    • Implemented extended slide policy [@maxee];
    • New skip button for DefaultIntro2 [@timobaehr];
    • Bug fixes and improvements;
    Source code(tar.gz)
    Source code(zip)
    example-release.apk(1.60 MB)
  • v3.3.0(Nov 28, 2015)

    How to update

    Add this to your build.gradle:

    repositories {
        mavenCentral()
    }
    
    dependencies {
      compile 'com.github.paolorotolo:appintro:3.3.0'
    }
    

    Changelog:

    • Added support for swipe locking (@danluong)
    • Added support for custom animation times (@BugsBunnyBR)
    • Added support for showing/hiding statusbar (@Andrew-Quebe)
    • Added support for changing nav bar color (@Andrew-Quebe)
    • Fixed #72
    • Fixed #74
    • Added support for Android 6.0 permissions (@Andrew-Quebe, @PaoloRotolo)

    Source code(tar.gz)
    Source code(zip)
    appintro-example.apk(1.51 MB)
  • v3.2.0(Aug 4, 2015)

    How to update

    Add this to your build.gradle:

    repositories {
        mavenCentral()
    }
    
    dependencies {
      compile 'com.github.paolorotolo:appintro:3.2.0'
    }
    

    Changelog:

    • Hide the indicator when there is only one slide [https://github.com/PaoloRotolo/AppIntro/commit/3ba5854f7e41b9883cbd0745bacc0d6eef204ef7];
    • Remove deprecation warning for Resources.getDrawable(int) [https://github.com/PaoloRotolo/AppIntro/commit/45e61d31bfb049cdd8f671b68e22285576d957d2];
    • Extend AppCompatActivity, update support libs [https://github.com/PaoloRotolo/AppIntro/commit/ded7efa471054b21a7e701f22c1bfcf0377fd075];
    • New getPager() method [https://github.com/PaoloRotolo/AppIntro/commit/a7fd4025eb7bc08e9049812b7a5df6ea9b116bc4];
    • Fix for page indicator being off center [https://github.com/PaoloRotolo/AppIntro/commit/9cd45d8e5d43d360e69fa39a782fe280498760b0];
    • Fixed button background color on < Lollipop [https://github.com/PaoloRotolo/AppIntro/commit/7278ff3e658711576371f977a7a235f086009de3];
    • Removed deprecated library NineOldAndroids (minSdkVersion = 14) [https://github.com/PaoloRotolo/AppIntro/commit/8e3f3ac2f63c26496002b954f474f6d134a4a98a];
    Source code(tar.gz)
    Source code(zip)
    appintro-3.2.0-sources.jar(10.93 KB)
    appintro-example-3.2.0.apk(1.38 MB)
Owner
AppIntro Team
Developers of AppIntro library
AppIntro Team
Make interesting books for your kids, usint text and images from simple.wikipedia.org

Baby Book Builder Baby Book Builder is an Android app and a website for creating books to help your growing child learn. Contributing Donations Baby B

Baby Apps 11 Nov 19, 2022
Joker-App - List application tha make requests to a Chuck Norris Api

Joker App About • Technologies • Features • Author • License ?? About the Projec

Miguel S. da Silva 1 Feb 4, 2022
Android Library to make SharedPreferences usage easier.

KotlinPreferences Kotlin Android Library, that makes preference usage simple and fun. KotlinPreferences now have a brother. With KotlinPreferences, yo

Marcin Moskała 50 Nov 6, 2022
A collection of small utility functions to make it easier to deal with some otherwise nullable APIs on Android.

requireKTX requireKTX is a collection of small utility functions to make it easier to deal with some otherwise nullable APIs on Android, using the sam

Márton Braun 82 Oct 1, 2022
ZoomHelper will make any view to be zoomable just like Instagram pinch-to-zoom

ZoomHelper ZoomHelper will make any view to be zoomable just like the Instagram pinch-to-zoom. ?? Installation ZoomHelper is available in the JCenter,

AmirHosseinAghajari 238 Dec 25, 2022
A simple and easy adapter for RecyclerView. You don't have to make adapters and view holders anymore. Slush will help you.

한국어 No more boilerplate adapters and view holders. Slush will make using RecyclerView easy and fast. The goal of this project is to make RecyclerView,

SeungHyun 26 Sep 13, 2022
A small DSL to make building a conversation in Bukkit easy.

Konversation Konversation provides a simple builder to construct chains of prompts to be used in the conversation API present in Bukkit. Bukkit only p

Tim Hagemann 2 Dec 4, 2022
Kstr is a set of helpful methods library for Kotlin intended for make the developer life easier.

Kstr is a set of helpful methods library for Kotlin intended for make the developer life easier. Kstr uses the powerful feature of extension func

Rafael Acioly 0 Nov 3, 2021
Elixir is a library designed to make minecraft login easier.

Elixir Elixir is a library designed to make minecraft login easier. Usage We have a maven repo for this project. repositories { maven { url = "htt

null 4 Aug 11, 2022
A somewhat copy past of Jetbrain's code from the kotlin plugin repo to make it humanly possible to test Intellij IDEA kotlin plugins that work on kotlin

A somewhat copy past of Jetbrain's code from the kotlin plugin repo to make it humanly possible to test Intellij IDEA kotlin plugins that work on kotlin

common sense OSS 0 Jan 20, 2022
This program will read from your android application string.xml file and generate translated strings.xml files in your preferred languages using google sheet.

Localize your application content This program will read from your application string.xml file and generate translated strings.xml files in your prefe

DhiWise 4 Jul 29, 2022
Name of your app is an android app that allows building a todo list

Project 1 - SimpleToDo Name of your app is an android app that allows building a todo list and basic todo items management functionality including add

Javier Nazario 0 Nov 23, 2021
A secure, opensource android app to store your bank accounts, cards, and credentials. Locally and securely.

Digital Tijori ?? Digital Tijori app lets you store your bank accounts, cards and credentials. You can link cards and credentials to a particular bank

Harsh Nandwani 8 Aug 26, 2022
Just an app with lame dad jokes content to fill up your day.

Just an app with lame dad jokes content to fill up your day. MVP This MVP version features: Feed walks you through the latest dad jokes, Browse back s

null 240 Dec 20, 2022
Reapp is everything you need to build amazing apps with React: a collection of packages that work together, our UI kit, and a CLI that scaffolds your app and includes a server and build system.

What is it? Reapp is everything you need to build amazing apps with React: a collection of packages that work together, our UI kit, and a CLI that sca

reapp 3.4k Nov 20, 2022
Kamper - a small KMM/KMP library that provides performance monitoring for your app.

?? Kamper Kamper is a KMP/KMM library that implements a unified way to track application performances. The solution is based on plugin design patterns

S. Mellouk 31 Jun 10, 2022
HowsTheWeather - 🌄 Your typical weather app, made really simple.

How's The Weather This is a simple Android app made with the purpose of learning how to access external APIs. It displays the data fetched from this A

Sam Garcia 1 Jan 3, 2022
Schedule-4-me is an opinionated to-do app to bring chaos to your life.

Schedule-4-me Have you ever had too much control in your life? Ever find yourself stuck at home repeating the same motions over and over again? Well f

null 4 Jan 16, 2022
Open as default - A flutter plugin that allows setting up your flutter app to open files as default

open_as_default A flutter plugin that allows setting up your flutter app to open

LuisDeLaValier 3 Nov 15, 2022