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

Commit 77b718ef authored by Zekan Qian's avatar Zekan Qian
Browse files

Add PageModel framework, and use it in ArgumentPageModel.

Bug: 244122804
Test: manual - build Spa gallery
Change-Id: I7079bfdcf84820a1d499be3efe65f9a046d7ab08
parent dccbbc0b
Loading
Loading
Loading
Loading
+2 −10
Original line number Diff line number Diff line
@@ -47,16 +47,8 @@ object SpaEnvironment {
                FooterPageProvider,
            ),
            rootPageData = listOf(
                SettingsPage(HomePageProvider.name),
                SettingsPage(
                    ArgumentPageProvider.name,
                    ArgumentPageProvider.buildArgument("foo")
                ),
                SettingsPage(
                    ArgumentPageProvider.name,
                    ArgumentPageProvider.buildArgument("bar")
                ),
            )
                SettingsPage(HomePageProvider.name)
            ) + ArgumentPageProvider.buildRootPages()
        )
    }

+48 −80
Original line number Diff line number Diff line
@@ -19,64 +19,47 @@ package com.android.settingslib.spa.gallery.page
import android.os.Bundle
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import androidx.navigation.NamedNavArgument
import androidx.navigation.NavType
import androidx.navigation.navArgument
import com.android.settingslib.spa.framework.common.SettingsEntry
import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
import com.android.settingslib.spa.framework.common.SettingsPage
import com.android.settingslib.spa.framework.common.SettingsPageProvider
import com.android.settingslib.spa.framework.compose.navigator
import com.android.settingslib.spa.framework.compose.toState
import com.android.settingslib.spa.framework.theme.SettingsTheme
import com.android.settingslib.spa.framework.util.getIntArg
import com.android.settingslib.spa.framework.util.getStringArg
import com.android.settingslib.spa.framework.util.navLink
import com.android.settingslib.spa.framework.util.normalize
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
import com.android.settingslib.spa.widget.scaffold.RegularScaffold

private const val TITLE = "Sample page with arguments"
private const val STRING_PARAM_NAME = "stringParam"
private const val INT_PARAM_NAME = "intParam"

object ArgumentPageProvider : SettingsPageProvider {
    override val name = "Argument"
    override val name = ArgumentPageModel.name

    override val parameter = listOf(
        navArgument(STRING_PARAM_NAME) { type = NavType.StringType },
        navArgument(INT_PARAM_NAME) { type = NavType.IntType },
    )
    override val parameter = ArgumentPageModel.parameter

    override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
        if (!parameter.isValid(arguments)) return emptyList()
        if (!ArgumentPageModel.isValidArgument(arguments)) return emptyList()

        val owner = SettingsPage(name, parameter.normalize(arguments))
        val entryList = mutableListOf<SettingsEntry>()
        val stringParamEntry = SettingsEntryBuilder.create("string_param", owner)
        stringParamEntry.setUiLayoutFn {
            Preference(object : PreferenceModel {
                override val title = "String param value"
                override val summary =
                    parameter.getStringArg(STRING_PARAM_NAME, arguments)!!.toState()
            })
        }
        entryList.add(stringParamEntry.build())
        entryList.add(
            SettingsEntryBuilder.create("string_param", owner)
                // Set attributes
                .setIsAllowSearch(true)
                .setUiLayoutFn {
                    // Set ui rendering
                    Preference(ArgumentPageModel.create(arguments).genStringParamPreferenceModel())
                }.build()
        )

        val intParamEntry = SettingsEntryBuilder.create("int_param", owner)
        intParamEntry.setUiLayoutFn {
            Preference(object : PreferenceModel {
                override val title = "Int param value"
                override val summary =
                    parameter.getIntArg(INT_PARAM_NAME, arguments)!!.toString().toState()
            })
        }
        entryList.add(intParamEntry.build())
        entryList.add(
            SettingsEntryBuilder.create("int_param", owner)
                // Set attributes
                .setIsAllowSearch(true)
                .setUiLayoutFn {
                    // Set ui rendering
                    Preference(ArgumentPageModel.create(arguments).genIntParamPreferenceModel())
                }.build()
        )

        val intParam = parameter.getIntArg(INT_PARAM_NAME, arguments)
        val entryFoo = buildInjectEntry(buildNextArgument("foo", intParam))
        val entryBar = buildInjectEntry(buildNextArgument("bar", intParam))
        val entryFoo = buildInjectEntry(ArgumentPageModel.buildNextArgument("foo", arguments))
        val entryBar = buildInjectEntry(ArgumentPageModel.buildNextArgument("bar", arguments))
        if (entryFoo != null) entryList.add(entryFoo.setLink(fromPage = owner).build())
        if (entryBar != null) entryList.add(entryBar.setLink(fromPage = owner).build())

@@ -84,30 +67,33 @@ object ArgumentPageProvider : SettingsPageProvider {
    }

    private fun buildInjectEntry(arguments: Bundle?): SettingsEntryBuilder? {
        if (!parameter.isValid(arguments)) return null

        val seBuilder =
            SettingsEntryBuilder.createInject(name, parameter.normalize(arguments))
        seBuilder.setIsAllowSearch(false)

        seBuilder.setUiLayoutFn {
            val summaryArray = listOf(
                "$STRING_PARAM_NAME=" + parameter.getStringArg(STRING_PARAM_NAME, arguments)!!,
                "$INT_PARAM_NAME=" + parameter.getIntArg(INT_PARAM_NAME, arguments)!!
            )
            Preference(object : PreferenceModel {
                override val title = TITLE
                override val summary = summaryArray.joinToString(", ").toState()
                override val onClick = navigator(name + parameter.navLink(arguments))
            })
        if (!ArgumentPageModel.isValidArgument(arguments)) return null

        return SettingsEntryBuilder.createInject(name, parameter.normalize(arguments))
            // Set attributes
            .setIsAllowSearch(false)
            .setUiLayoutFn {
                // Set ui rendering
                Preference(ArgumentPageModel.create(arguments).genInjectPreferenceModel())
            }
    }

        return seBuilder
    fun buildRootPages(): List<SettingsPage> {
        return listOf(
            SettingsPage(
                ArgumentPageModel.name,
                ArgumentPageModel.buildArgument("foo")
            ),
            SettingsPage(
                ArgumentPageModel.name,
                ArgumentPageModel.buildArgument("bar")
            ),
        )
    }

    @Composable
    override fun Page(arguments: Bundle?) {
        RegularScaffold(title = TITLE) {
        RegularScaffold(title = ArgumentPageModel.create(arguments).genPageTitle()) {
            for (entry in buildEntry(arguments)) {
                entry.uiLayout()
            }
@@ -116,21 +102,8 @@ object ArgumentPageProvider : SettingsPageProvider {

    @Composable
    fun EntryItem(stringParam: String, intParam: Int) {
        buildInjectEntry(buildArgument(stringParam, intParam))?.build()?.uiLayout?.let { it() }
    }

    fun buildArgument(stringParam: String, intParam: Int? = null): Bundle {
        val args = Bundle()
        args.putString(STRING_PARAM_NAME, stringParam)
        if (intParam != null) args.putInt(INT_PARAM_NAME, intParam)
        return args
    }

    private fun buildNextArgument(stringParam: String, intParam: Int? = null): Bundle {
        return if (intParam == null)
            buildArgument(stringParam)
        else
            buildArgument(stringParam, intParam + 1)
        buildInjectEntry(ArgumentPageModel.buildArgument(stringParam, intParam))
            ?.build()?.uiLayout?.let { it() }
    }
}

@@ -139,12 +112,7 @@ object ArgumentPageProvider : SettingsPageProvider {
private fun ArgumentPagePreview() {
    SettingsTheme {
        ArgumentPageProvider.Page(
            ArgumentPageProvider.buildArgument(stringParam = "foo", intParam = 0)
            ArgumentPageModel.buildArgument(stringParam = "foo", intParam = 0)
        )
    }
}

private fun List<NamedNavArgument>.isValid(arguments: Bundle?): Boolean {
    val stringParam = getStringArg(STRING_PARAM_NAME, arguments)
    return (stringParam != null && listOf("foo", "bar").contains(stringParam))
}
+123 −0
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.gallery.page

import android.os.Bundle
import android.util.Log
import androidx.compose.runtime.Composable
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavType
import androidx.navigation.navArgument
import com.android.settingslib.spa.framework.common.PageModel
import com.android.settingslib.spa.framework.compose.navigator
import com.android.settingslib.spa.framework.compose.stateOf
import com.android.settingslib.spa.framework.util.getIntArg
import com.android.settingslib.spa.framework.util.getStringArg
import com.android.settingslib.spa.framework.util.navLink
import com.android.settingslib.spa.widget.preference.PreferenceModel

private const val TITLE = "Sample page with arguments"
private const val STRING_PARAM_NAME = "stringParam"
private const val INT_PARAM_NAME = "intParam"

class ArgumentPageModel : PageModel() {

    companion object {
        const val name = "Argument"
        val parameter = listOf(
            navArgument(STRING_PARAM_NAME) { type = NavType.StringType },
            navArgument(INT_PARAM_NAME) { type = NavType.IntType },
        )

        fun buildArgument(stringParam: String, intParam: Int? = null): Bundle {
            val args = Bundle()
            args.putString(STRING_PARAM_NAME, stringParam)
            if (intParam != null) args.putInt(INT_PARAM_NAME, intParam)
            return args
        }

        fun buildNextArgument(newStringParam: String, arguments: Bundle? = null): Bundle {
            val intParam = parameter.getIntArg(INT_PARAM_NAME, arguments)
            return if (intParam == null)
                buildArgument(newStringParam)
            else
                buildArgument(newStringParam, intParam + 1)
        }

        fun isValidArgument(arguments: Bundle?): Boolean {
            val stringParam = parameter.getStringArg(STRING_PARAM_NAME, arguments)
            return (stringParam != null && listOf("foo", "bar").contains(stringParam))
        }

        @Composable
        fun create(arguments: Bundle?): ArgumentPageModel {
            val pageModel: ArgumentPageModel = viewModel(key = arguments.toString())
            pageModel.initOnce(arguments)
            return pageModel
        }
    }

    private val title = TITLE
    private var arguments: Bundle? = null
    private var stringParam: String? = null
    private var intParam: Int? = null

    override fun initialize(arguments: Bundle?) {
        logMsg("init with args " + arguments.toString())
        this.arguments = arguments
        stringParam = parameter.getStringArg(STRING_PARAM_NAME, arguments)
        intParam = parameter.getIntArg(INT_PARAM_NAME, arguments)
    }

    @Composable
    fun genPageTitle(): String {
        return title
    }

    @Composable
    fun genStringParamPreferenceModel(): PreferenceModel {
        return object : PreferenceModel {
            override val title = "String param value"
            override val summary = stateOf(stringParam!!)
        }
    }

    @Composable
    fun genIntParamPreferenceModel(): PreferenceModel {
        return object : PreferenceModel {
            override val title = "Int param value"
            override val summary = stateOf(intParam!!.toString())
        }
    }

    @Composable
    fun genInjectPreferenceModel(): PreferenceModel {
        val summaryArray = listOf(
            "$STRING_PARAM_NAME=" + stringParam!!,
            "$INT_PARAM_NAME=" + intParam!!
        )
        return object : PreferenceModel {
            override val title = genPageTitle()
            override val summary = stateOf(summaryArray.joinToString(", "))
            override val onClick = navigator(name + parameter.navLink(arguments))
        }
    }
}

private fun logMsg(message: String) {
    Log.d("ArgumentPageModel", message)
}
+33 −0
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.framework.common

import android.os.Bundle
import androidx.lifecycle.ViewModel

open class PageModel : ViewModel() {
    var initialized = false

    fun initOnce(arguments: Bundle?) {
        // Initialize only once
        if (initialized) return
        initialized = true
        initialize(arguments)
    }

    open fun initialize(arguments: Bundle?) {}
}
+1 −1
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@ package com.android.settingslib.spa.framework.common
import android.util.Log
import java.util.LinkedList

const val MAX_ENTRY_SIZE = 5000
private const val MAX_ENTRY_SIZE = 5000

/**
 * The repository to maintain all Settings entries