Skip to content

1: Setup

Kieron Quinn edited this page Jun 27, 2021 · 6 revisions

MonetCompat supports Android 5.0 and above (in compatibility mode - see below), and Android 8.1 and above without compatibility mode. It's easy to implement, and gives you full control over where and how the colors should be used.

Adding dependencies

MonetCompat is available on JitPack, you can find the latest release here.

Setting up JitPack in Gradle is easy, if you've not done so already. Add JitPack as a Maven repository in your project level build.gradle:

allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
}

Then add MonetCompat as a dependency to your app level build.gradle:

JitPack badge

implementation 'com.github.KieronQuinn:MonetCompat:version'

Palette Compatibility Mode

If your app supports Android 8.0 and below (down to Android 5.0), you must also include the androidx.palette dependency, if you don't already:

implementation 'androidx.palette:palette:1.0.0'

You must also call the static MonetCompat.enablePaletteCompat() method before using Monet, ideally in your Application class. Failure to include the Palette dependency and then calling the method will result in an intentional crash (following a dependency check), on all Android versions.

Note: The Android documentation for WallpaperManager.getDrawable() (which is used by MonetCompat to feed into Palette on Android < 8.1) suggests that android.permission.READ_EXTERNAL_STORAGE may be required on some devices to call the method, however it is not clear which Android version introduced this requirement (it seems to have been added to the docs at some point in 2020 with no min version). During testing, I was able to get valid colors from the method without the permission granted, testing on devices between Android 5.0 and 8.0 (getWallpaperColors() never needs the permission). According to the docs, if the permission is required and not granted, the method will return null. If this happens, MonetCompat will simply use the default color you provide, until the user grants storage permissions and restarts the app.

MonetCompat is designed to handle color changes similarly to configuration changes - that is, with the standard setup (detailed below), it will recreate an activity if/when the Monet colors change (eg. if the user changes their wallpaper). If your app is built to handle configuration changes, such as rotations or UI mode changes already, adding Monet is therefore very simple.

Activities

Extend from MonetCompatActivity in place of AppCompatActivity, for example:

class MainActivity: MonetCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // Set up your activity as normal
    }

}

This will make your activity automatically restart when Monet's colors are changed, and provides an optional method, onMonetColorsChanged:

override fun onMonetColorsChanged(monet: MonetCompat, monetColors: DynamicColorScheme, isInitialChange: Boolean) {
   // Called when Monet's colors are either initially loaded (isInitialChange = false) or have changed, *if recreation is disabled*
}

This method allows you to update your currently loaded activity (or await Monet before calling setContentView - see the coroutines section below for an ideal way of doing that), or...

Disabling automatic recreation

If you would prefer MonetCompat to not automatically recreate your activity when the colors have changed, simply override the recreateMode field in your activity to be false. You are then free to handle changes yourself, either on the activity level (in the method detailed above), or in your fragments via the same override.

Coroutines

Ideally, you should await Monet being available before showing your activity to the user. The best way to do this is to use a Coroutine, as follows:

class MainActivity: MonetCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        lifecycleScope.launchWhenCreated {
            monet.awaitMonetReady()
            setContentView(R.layout.activity_main)
        }
    }
}

Obviously, this has the effect of delaying your app content from displaying to the user until Monet is available - which, while it should be almost instant, may in some cases be a bit slower. How you handle this is up to you, but you may wish to set your theme's android:windowBackground to a splash screen if you have not done so already (see here for an example), which will continue to be displayed in the interim with this code.

Fragments

You may optionally extend from MonetFragment, if you would like easy access to the MonetCompat instance, or to use onMonetColorsChanged as detailed above. Note that in this case, onMonetColorsChanged is only useful to you if you have recreate mode disabled in the activity, as the fragment will be destroyed and recreated otherwise.

Example

Recreate mode enabled

class MainFragment: MonetFragment(R.layout.fragment_main){

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        view.applyMonetRecursively()
    }

}

Note: You may also call applyMonetRecursively in onCreateView, for the color changes to be applied to the inflated view before it is even passed to the superclass.

Recreate mode disabled

class MainFragment: MonetFragment(R.layout.fragment_main){

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        //Set up your view as normal
    }

    override fun onMonetColorsChanged(monet: MonetCompat, monetColors: DynamicColorScheme, isInitialChange: Boolean) {
        //This will apply colors once ready
        view?.applyMonetRecursively()
    }

}

Clone this wiki locally