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

Commit 09d46e05 authored by Chaohui Wang's avatar Chaohui Wang
Browse files

[Spa] New Card widget

With icon, title, text and buttons.

Bug: 305856149
Test: Run Gallery
Test: unit test
Change-Id: Idd6ab553646f0f9e9307b3a517b39098577244a2
parent 7c10e57c
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -26,4 +26,9 @@
    <string name="single_line_summary_preference_summary" translatable="false">A very long summary to show case a preference which only shows a single line summary.</string>
    <!-- Footer text with two links. [DO NOT TRANSLATE] -->
    <string name="footer_with_two_links" translatable="false">Annotated string with <a href="https://www.android.com/">link 1</a> and <a href="https://source.android.com/">link 2</a>.</string>

    <!-- Sample title -->
    <string name="sample_title" translatable="false">Lorem ipsum</string>
    <!-- Sample text -->
    <string name="sample_text" translatable="false">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent a rhoncus tellus. Nulla facilisi. Pellentesque erat ex, maximus viae turpis</string>
</resources>
+2 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import com.android.settingslib.spa.framework.common.SettingsPageProviderReposito
import com.android.settingslib.spa.framework.common.SpaEnvironment
import com.android.settingslib.spa.framework.common.createSettingsPage
import com.android.settingslib.spa.gallery.button.ActionButtonPageProvider
import com.android.settingslib.spa.gallery.card.CardPageProvider
import com.android.settingslib.spa.gallery.chart.ChartPageProvider
import com.android.settingslib.spa.gallery.dialog.AlertDialogPageProvider
import com.android.settingslib.spa.gallery.editor.EditorMainPageProvider
@@ -96,6 +97,7 @@ class GallerySpaEnvironment(context: Context) : SpaEnvironment(context) {
                SettingsExposedDropdownMenuCheckBoxProvider,
                SettingsTextFieldPasswordPageProvider,
                SearchScaffoldPageProvider,
                CardPageProvider,
            ),
            rootPages = listOf(
                HomePageProvider.createSettingsPage(),
+93 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.gallery.card

import android.os.Bundle
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.WarningAmber
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
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.card.CardButton
import com.android.settingslib.spa.widget.card.SettingsCard
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
import com.android.settingslib.spa.widget.scaffold.RegularScaffold

object CardPageProvider : SettingsPageProvider {
    override val name = "ActionButton"

    override fun getTitle(arguments: Bundle?) = TITLE

    @Composable
    override fun Page(arguments: Bundle?) {
        RegularScaffold(title = TITLE) {
            SettingsCardWithIcon()
            SettingsCardWithoutIcon()
        }
    }

    @Composable
    private fun SettingsCardWithIcon() {
        SettingsCard(
            title = stringResource(R.string.sample_title),
            text = stringResource(R.string.sample_text),
            imageVector = Icons.Outlined.WarningAmber,
            buttons = listOf(
                CardButton(text = "Action") {},
                CardButton(text = "Action", isMain = true) {},
            )
        )
    }

    @Composable
    private fun SettingsCardWithoutIcon() {
        SettingsCard(
            title = stringResource(R.string.sample_title),
            text = stringResource(R.string.sample_text),
            buttons = listOf(
                CardButton(text = "Action") {},
            )
        )
    }

    fun buildInjectEntry(): SettingsEntryBuilder {
        return SettingsEntryBuilder.createInject(owner = createSettingsPage())
            .setUiLayoutFn {
                Preference(object : PreferenceModel {
                    override val title = TITLE
                    override val onClick = navigator(name)
                })
            }
    }

    private const val TITLE = "Sample Card"
}

@Preview
@Composable
private fun CardPagePreview() {
    SettingsTheme {
        CardPageProvider.Page(null)
    }
}
+2 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import com.android.settingslib.spa.framework.theme.SettingsTheme
import com.android.settingslib.spa.gallery.R
import com.android.settingslib.spa.gallery.SettingsPageProviderEnum
import com.android.settingslib.spa.gallery.button.ActionButtonPageProvider
import com.android.settingslib.spa.gallery.card.CardPageProvider
import com.android.settingslib.spa.gallery.chart.ChartPageProvider
import com.android.settingslib.spa.gallery.dialog.AlertDialogPageProvider
import com.android.settingslib.spa.gallery.editor.EditorMainPageProvider
@@ -69,6 +70,7 @@ object HomePageProvider : SettingsPageProvider {
            ChartPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
            AlertDialogPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
            EditorMainPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
            CardPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
        )
    }

+164 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.card

import android.content.res.Configuration
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.WarningAmber
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.tooling.preview.Preview
import com.android.settingslib.spa.framework.theme.SettingsDimension
import com.android.settingslib.spa.framework.theme.SettingsShape.CornerExtraLarge
import com.android.settingslib.spa.framework.theme.SettingsTheme
import com.android.settingslib.spa.widget.ui.SettingsBody
import com.android.settingslib.spa.widget.ui.SettingsTitle

data class CardButton(
    val text: String,
    val isMain: Boolean = false,
    val onClick: () -> Unit,
)

@Composable
fun SettingsCard(
    title: String,
    text: String,
    imageVector: ImageVector? = null,
    buttons: List<CardButton> = emptyList(),
) {
    Card(
        shape = CornerExtraLarge,
        colors = CardDefaults.cardColors(
            containerColor = SettingsTheme.colorScheme.surface,
        ),
        modifier = Modifier
            .fillMaxWidth()
            .padding(
                horizontal = SettingsDimension.itemPaddingEnd,
                vertical = SettingsDimension.itemPaddingAround,
            ),
    ) {
        Column(
            modifier = Modifier.padding(SettingsDimension.itemPaddingStart),
            verticalArrangement = Arrangement.spacedBy(SettingsDimension.itemPaddingAround)
        ) {
            CardIcon(imageVector)
            SettingsTitle(title)
            SettingsBody(text)
            Buttons(buttons)
        }
    }
}

@Composable
private fun CardIcon(imageVector: ImageVector?) {
    if (imageVector != null) {
        Icon(
            imageVector = imageVector,
            contentDescription = null,
            modifier = Modifier.size(SettingsDimension.itemIconSize),
            tint = MaterialTheme.colorScheme.primary,
        )
    }
}

@Composable
private fun Buttons(buttons: List<CardButton>) {
    if (buttons.isNotEmpty()) {
        Row(
            modifier = Modifier
                .fillMaxWidth()
                .padding(top = SettingsDimension.itemPaddingAround),
            horizontalArrangement = Arrangement.spacedBy(
                space = SettingsDimension.itemPaddingEnd,
                alignment = Alignment.End,
            ),
        ) {
            for (button in buttons) {
                Button(button)
            }
        }
    }
}

@Composable
private fun Button(button: CardButton) {
    if (button.isMain) {
        Button(
            onClick = button.onClick,
            colors = ButtonDefaults.buttonColors(
                containerColor = SettingsTheme.colorScheme.primaryContainer,
            ),
        ) {
            Text(
                text = button.text,
                color = SettingsTheme.colorScheme.onPrimaryContainer,
            )
        }
    } else {
        OutlinedButton(onClick = button.onClick) {
            Text(
                text = button.text,
                color = MaterialTheme.colorScheme.onSurface,
            )
        }
    }
}

@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO)
@Composable
private fun SettingsCardPreviewLight() {
    SettingsCardPreview()
}

@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun SettingsCardPreviewDark() {
    SettingsCardPreview()
}

@Composable
private fun SettingsCardPreview() {
    SettingsTheme {
        SettingsCard(
            title = "Lorem ipsum",
            text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
            imageVector = Icons.Outlined.WarningAmber,
            buttons = listOf(
                CardButton(text = "Action") {},
                CardButton(text = "Action", isMain = true) {},
            )
        )
    }
}
Loading