Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0410444a authored by Chaohui Wang's avatar Chaohui Wang Committed by Android (Google) Code Review
Browse files

Merge "[Spa] Support preview Lottie file in gallery" into main

parents 07f9fe89 0ce77bfb
Loading
Loading
Loading
Loading
+55 −43
Original line number Diff line number Diff line
@@ -16,77 +16,89 @@

package com.android.settingslib.spa.gallery.page

import android.net.Uri
import android.os.Bundle
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.FileUpload
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.tooling.preview.Preview
import com.android.settingslib.spa.framework.common.SettingsEntry
import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
import com.airbnb.lottie.compose.LottieCompositionSpec
import com.android.settingslib.spa.framework.common.SettingsPageProvider
import com.android.settingslib.spa.framework.common.createSettingsPage
import com.android.settingslib.spa.framework.compose.navigator
import com.android.settingslib.spa.framework.theme.SettingsTheme
import com.android.settingslib.spa.gallery.R
import com.android.settingslib.spa.widget.button.CategoryButton
import com.android.settingslib.spa.widget.illustration.Illustration
import com.android.settingslib.spa.widget.illustration.IllustrationModel
import com.android.settingslib.spa.widget.illustration.ResourceType
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
import com.android.settingslib.spa.widget.scaffold.RegularScaffold
import com.android.settingslib.spa.widget.ui.CategoryTitle

private const val TITLE = "Sample Illustration"

object IllustrationPageProvider : SettingsPageProvider {
    override val name = "Illustration"
    private val owner = createSettingsPage()

    override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
        val entryList = mutableListOf<SettingsEntry>()
        entryList.add(
            SettingsEntryBuilder.create("Lottie Illustration", owner)
                .setUiLayoutFn {
                    Preference(object : PreferenceModel {
                        override val title = "Lottie Illustration"
                    })

                    Illustration(object : IllustrationModel {
                        override val resId = R.raw.accessibility_shortcut_type_triple_tap
                        override val resourceType = ResourceType.LOTTIE
                    })
                }.build()
    @Composable
    override fun Page(arguments: Bundle?) {
        RegularScaffold(TITLE) {
            CategoryTitle("Lottie Illustration")
            var lottieSpec: LottieCompositionSpec by remember {
                mutableStateOf(
                    LottieCompositionSpec.RawRes(R.raw.accessibility_shortcut_type_triple_tap)
                )
        entryList.add(
            SettingsEntryBuilder.create("Image Illustration", owner)
                .setUiLayoutFn {
                    Preference(object : PreferenceModel {
                        override val title = "Image Illustration"
                    })
            }
            Illustration(lottieSpec)
            JsonFileUploadButton { uri ->
                if (uri != null) {
                    lottieSpec = LottieCompositionSpec.ContentProvider(uri)
                }
            }

                    Illustration(object : IllustrationModel {
            CategoryTitle("Image Illustration")
            Illustration(
                object : IllustrationModel {
                    override val resId = R.drawable.accessibility_captioning_banner
                    override val resourceType = ResourceType.IMAGE
                    })
                }.build()
                }
            )

        return entryList
        }
    }

    @Composable
    fun Entry() {
        Preference(object : PreferenceModel {
        Preference(
            object : PreferenceModel {
                override val title = TITLE
                override val onClick = navigator(name)
        })
            }
        )
    }
}

    override fun getTitle(arguments: Bundle?): String {
        return TITLE
@Composable
fun JsonFileUploadButton(onResult: (Uri?) -> Unit) {
    val launcher =
        rememberLauncherForActivityResult(
            contract = ActivityResultContracts.GetContent(),
            onResult = onResult,
        )

    CategoryButton(Icons.Outlined.FileUpload, "Upload JSON File") {
        launcher.launch("application/json")
    }
}

@Preview(showBackground = true)
@Preview
@Composable
private fun IllustrationPagePreview() {
    SettingsTheme {
        IllustrationPageProvider.Page(null)
    }
    SettingsTheme { IllustrationPageProvider.Page(null) }
}
+1 −1
Original line number Diff line number Diff line
@@ -62,8 +62,8 @@ dependencies {
    api("androidx.window:window:1.5.0-alpha02")
    api("com.github.PhilJay:MPAndroidChart:v3.1.0-alpha") // external/MPAndroidChart
    api("com.google.android.material:material:1.13.0-alpha13") // prebuilts/sdk/current/extras/material-design-x
    api("com.airbnb.android:lottie-compose:6.5.2") // external/lottie
    debugApi("androidx.compose.ui:ui-tooling:$jetpackComposeVersion")
    implementation("com.airbnb.android:lottie-compose:6.5.2") // external/lottie

    androidTestImplementation(project(":Spa:testutils"))
    androidTestImplementation(libs.dexmaker.mockito)
+46 −42
Original line number Diff line number Diff line
@@ -16,7 +16,9 @@

package com.android.settingslib.spa.widget.illustration

import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
@@ -27,18 +29,19 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import com.airbnb.lottie.compose.LottieCompositionSpec
import com.android.settingslib.spa.framework.theme.SettingsDimension
import com.android.settingslib.spa.widget.ui.ImageBox
import com.android.settingslib.spa.widget.ui.Lottie
enum class ResourceType { IMAGE, LOTTIE }

/**
 * The widget model for [Illustration] widget.
 */
enum class ResourceType {
    IMAGE,
    LOTTIE,
}

/** The widget model for [Illustration] widget. */
interface IllustrationModel {
    /**
     * The resource id of this [Illustration].
     */
    /** The resource id of this [Illustration]. */
    val resId: Int

    /**
@@ -56,47 +59,48 @@ interface IllustrationModel {
 */
@Composable
fun Illustration(model: IllustrationModel) {
    Illustration(
        resId = model.resId,
        resourceType = model.resourceType,
        modifier = Modifier,
    )
    Illustration { IllustrationContent(resId = model.resId, resourceType = model.resourceType) }
}

@Composable
fun Illustration(
    resId: Int,
    resourceType: ResourceType,
    modifier: Modifier = Modifier
) {
fun Illustration(spec: LottieCompositionSpec) {
    Illustration { Lottie(spec) }
}

@Composable
fun Illustration(resId: Int, resourceType: ResourceType, modifier: Modifier = Modifier) {
    Illustration(modifier) { IllustrationContent(resId, resourceType) }
}

@Composable
private fun IllustrationContent(resId: Int, resourceType: ResourceType) {
    when (resourceType) {
        ResourceType.LOTTIE -> {
            Lottie(resId = resId)
        }

        ResourceType.IMAGE -> {
            Image(painter = painterResource(resId), contentDescription = null)
        }
    }
}

@Composable
internal fun Illustration(modifier: Modifier = Modifier, content: @Composable () -> Unit) {
    Column(
        modifier = modifier
            .fillMaxWidth()
            .padding(horizontal = SettingsDimension.illustrationPadding),
        modifier =
            modifier.fillMaxWidth().padding(horizontal = SettingsDimension.illustrationPadding),
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        val illustrationModifier = modifier
            .sizeIn(
        Box(
            Modifier.sizeIn(
                    maxWidth = SettingsDimension.illustrationMaxWidth,
                    maxHeight = SettingsDimension.illustrationMaxHeight,
                )
                .clip(RoundedCornerShape(SettingsDimension.illustrationCornerRadius))
                .background(color = Color.Transparent)

        when (resourceType) {
            ResourceType.LOTTIE -> {
                Lottie(
                    resId = resId,
                    modifier = illustrationModifier,
                )
            }
            ResourceType.IMAGE -> {
                ImageBox(
                    resId = resId,
                    contentDescription = null,
                    modifier = illustrationModifier,
                )
            }
        ) {
            content()
        }
    }
}
+0 −39
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * 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.
 */

package com.android.settingslib.spa.widget.ui

import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource

@Composable
fun ImageBox(
    resId: Int,
    contentDescription: String?,
    modifier: Modifier = Modifier,
) {
    Box(
        modifier = modifier,
    ) {
        Image(
            painter = painterResource(resId),
            contentDescription = contentDescription,
        )
    }
}
+29 −32
Original line number Diff line number Diff line
@@ -36,19 +36,18 @@ import com.airbnb.lottie.compose.rememberLottieDynamicProperty
import com.android.settingslib.color.R

@Composable
fun Lottie(
    resId: Int,
    modifier: Modifier = Modifier,
) {
    Box(
        modifier = modifier,
    ) {
        BaseLottie(resId)
fun Lottie(resId: Int, modifier: Modifier = Modifier) {
    Lottie(spec = LottieCompositionSpec.RawRes(resId), modifier = modifier)
}

@Composable
fun Lottie(spec: LottieCompositionSpec, modifier: Modifier = Modifier) {
    Box(modifier = modifier) { BaseLottie(spec) }
}

object LottieColorUtils {
    private val DARK_TO_LIGHT_THEME_COLOR_MAP = mapOf(
    private val DARK_TO_LIGHT_THEME_COLOR_MAP =
        mapOf(
            ".grey200" to R.color.settingslib_color_grey800,
            ".grey600" to R.color.settingslib_color_grey400,
            ".grey800" to R.color.settingslib_color_grey300,
@@ -59,7 +58,7 @@ object LottieColorUtils {
            ".green400" to R.color.settingslib_color_green600,
            ".green200" to R.color.settingslib_color_green500,
            ".red200" to R.color.settingslib_color_red500,
        ".cream" to R.color.settingslib_color_charcoal
            ".cream" to R.color.settingslib_color_charcoal,
        )

    @Composable
@@ -68,8 +67,10 @@ object LottieColorUtils {
            val color = colorResource(colorRes).toArgb()
            rememberLottieDynamicProperty(
                property = LottieProperty.COLOR_FILTER,
                keyPath = arrayOf("**", key, "**")
            ){ PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP) }
                keyPath = arrayOf("**", key, "**"),
            ) {
                PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP)
            }
        }

    @Composable
@@ -78,14 +79,10 @@ object LottieColorUtils {
}

@Composable
private fun BaseLottie(resId: Int) {
    val composition by rememberLottieComposition(
        LottieCompositionSpec.RawRes(resId)
    )
    val progress by animateLottieCompositionAsState(
        composition,
        iterations = LottieConstants.IterateForever,
    )
private fun BaseLottie(spec: LottieCompositionSpec) {
    val composition by rememberLottieComposition(spec)
    val progress by
        animateLottieCompositionAsState(composition, iterations = LottieConstants.IterateForever)
    val isLightMode = !isSystemInDarkTheme()
    LottieAnimation(
        composition = composition,
Loading