Merge "Add device details more settings page" into main

This commit is contained in:
Haijie Hong
2024-08-20 09:43:30 +00:00
committed by Android (Google) Code Review
12 changed files with 428 additions and 118 deletions

View File

@@ -48,6 +48,7 @@ import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.bluetooth.ui.model.FragmentTypeModel;
import com.android.settings.bluetooth.ui.view.DeviceDetailsFragmentFormatter;
import com.android.settings.connecteddevice.stylus.StylusDevicesController;
import com.android.settings.core.SettingsUIDeviceConfig;
@@ -343,7 +344,7 @@ public class BluetoothDeviceDetailsFragment extends RestrictedDashboardFragment
public void onCreatePreferences(@NonNull Bundle savedInstanceState, @NonNull String rootKey) {
super.onCreatePreferences(savedInstanceState, rootKey);
if (Flags.enableBluetoothDeviceDetailsPolish()) {
mFormatter.updateLayout();
mFormatter.updateLayout(FragmentTypeModel.DeviceDetailsMainFragment.INSTANCE);
}
}
@@ -400,7 +401,9 @@ public class BluetoothDeviceDetailsFragment extends RestrictedDashboardFragment
@Override
protected void addPreferenceController(AbstractPreferenceController controller) {
if (Flags.enableBluetoothDeviceDetailsPolish()) {
List<String> keys = mFormatter.getVisiblePreferenceKeysForMainPage();
List<String> keys =
mFormatter.getVisiblePreferenceKeys(
FragmentTypeModel.DeviceDetailsMainFragment.INSTANCE);
Lifecycle lifecycle = getSettingsLifecycle();
if (keys == null || keys.contains(controller.getPreferenceKey())) {
super.addPreferenceController(controller);

View File

@@ -66,15 +66,14 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.DialogProperties
import com.android.settings.R
import com.android.settings.bluetooth.ui.model.DeviceSettingPreferenceModel
import com.android.settings.bluetooth.ui.composable.Icon as DeviceSettingComposeIcon
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingModel
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingStateModel
import com.android.settingslib.spa.framework.theme.SettingsDimension
import com.android.settingslib.spa.widget.dialog.getDialogWidth
@Composable
fun MultiTogglePreferenceGroup(
preferenceModels: List<DeviceSettingModel.MultiTogglePreference>,
preferenceModels: List<DeviceSettingPreferenceModel.MultiTogglePreference>,
) {
var settingIdForPopUp by remember { mutableStateOf<Int?>(null) }
@@ -115,7 +114,7 @@ fun MultiTogglePreferenceGroup(
colors = getButtonColors(preferenceModel.isActive),
contentPadding = PaddingValues(0.dp)) {
DeviceSettingComposeIcon(
preferenceModel.toggles[preferenceModel.state.selectedIndex]
preferenceModel.toggles[preferenceModel.selectedIndex]
.icon,
modifier = Modifier.size(24.dp))
}
@@ -144,7 +143,7 @@ private fun getButtonColors(isActive: Boolean) =
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun dialog(
multiTogglePreference: DeviceSettingModel.MultiTogglePreference,
multiTogglePreference: DeviceSettingPreferenceModel.MultiTogglePreference,
onDismiss: () -> Unit
) {
BasicAlertDialog(
@@ -179,7 +178,7 @@ private fun dialog(
}
@Composable
private fun dialogContent(multiTogglePreference: DeviceSettingModel.MultiTogglePreference) {
private fun dialogContent(multiTogglePreference: DeviceSettingPreferenceModel.MultiTogglePreference) {
Column {
Row(
modifier = Modifier.fillMaxWidth().height(24.dp),
@@ -219,7 +218,7 @@ private fun dialogContent(multiTogglePreference: DeviceSettingModel.MultiToggleP
}
Row {
for ((idx, toggle) in multiTogglePreference.toggles.withIndex()) {
val selected = idx == multiTogglePreference.state.selectedIndex
val selected = idx == multiTogglePreference.selectedIndex
Column(
modifier =
Modifier.weight(1f)
@@ -237,8 +236,7 @@ private fun dialogContent(multiTogglePreference: DeviceSettingModel.MultiToggleP
) {
Button(
onClick = {
multiTogglePreference.updateState(
DeviceSettingStateModel.MultiTogglePreferenceState(idx))
multiTogglePreference.onSelectedChange(idx)
},
modifier = Modifier.fillMaxSize(),
colors =

View File

@@ -0,0 +1,69 @@
/*
* Copyright (C) 2024 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.settings.bluetooth.ui.model
import com.android.settingslib.bluetooth.devicesettings.DeviceSettingId
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingIcon
import com.android.settingslib.bluetooth.devicesettings.shared.model.ToggleModel
/** Models a device setting preference. */
sealed interface DeviceSettingPreferenceModel {
@DeviceSettingId
val id: Int
/** Models a plain preference. */
data class PlainPreference(
@DeviceSettingId override val id: Int,
val title: String,
val summary: String? = null,
val icon: DeviceSettingIcon? = null,
val onClick: (() -> Unit)? = null,
) : DeviceSettingPreferenceModel
/** Models a switch preference. */
data class SwitchPreference(
@DeviceSettingId override val id: Int,
val title: String,
val summary: String? = null,
val icon: DeviceSettingIcon? = null,
val checked: Boolean,
val onCheckedChange: ((Boolean) -> Unit),
val onPrimaryClick: (() -> Unit)? = null,
) : DeviceSettingPreferenceModel
/** Models a multi-toggle preference. */
data class MultiTogglePreference(
@DeviceSettingId override val id: Int,
val title: String,
val toggles: List<ToggleModel>,
val isActive: Boolean,
val selectedIndex: Int,
val isAllowedChangingState: Boolean,
val onSelectedChange: (Int) -> Unit,
) : DeviceSettingPreferenceModel
/** Models a footer preference. */
data class FooterPreference(
@DeviceSettingId override val id: Int,
val footerText: String,
) : DeviceSettingPreferenceModel
/** Models a preference which could navigate to more settings fragment. */
data class MoreSettingsPreference(
@DeviceSettingId override val id: Int,
) : DeviceSettingPreferenceModel
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2024 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.settings.bluetooth.ui.model
/** Models a device details fragment type. */
sealed interface FragmentTypeModel {
/** Device details main page. */
data object DeviceDetailsMainFragment : FragmentTypeModel
/** Device details more settings page. */
data object DeviceDetailsMoreSettingsFragment : FragmentTypeModel
}

View File

@@ -19,47 +19,52 @@ package com.android.settings.bluetooth.ui.view
import android.bluetooth.BluetoothAdapter
import android.content.Context
import android.media.AudioManager
import android.util.Log
import android.os.Bundle
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope
import androidx.preference.Preference
import com.android.settings.R
import com.android.settings.SettingsPreferenceFragment
import com.android.settings.bluetooth.ui.composable.Icon
import com.android.settings.bluetooth.ui.composable.MultiTogglePreferenceGroup
import com.android.settings.bluetooth.ui.layout.DeviceSettingLayout
import com.android.settings.bluetooth.ui.model.DeviceSettingPreferenceModel
import com.android.settings.bluetooth.ui.model.FragmentTypeModel
import com.android.settings.bluetooth.ui.view.DeviceDetailsMoreSettingsFragment.Companion.KEY_DEVICE_ADDRESS
import com.android.settings.bluetooth.ui.viewmodel.BluetoothDeviceDetailsViewModel
import com.android.settings.core.SubSettingLauncher
import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
import com.android.settings.spa.preference.ComposePreference
import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingConfigItemModel
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingModel
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingStateModel
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingIcon
import com.android.settingslib.spa.framework.theme.SettingsDimension
import com.android.settingslib.spa.widget.preference.Preference as SpaPreference
import com.android.settingslib.spa.widget.preference.PreferenceModel
import com.android.settingslib.spa.widget.preference.SwitchPreference
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
import com.android.settingslib.spa.widget.preference.TwoTargetSwitchPreference
import com.android.settingslib.spa.widget.ui.Footer
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.runBlocking
import com.android.settingslib.spa.widget.preference.Preference as SpaPreference
/** Handles device details fragment layout according to config. */
interface DeviceDetailsFragmentFormatter {
/** Gets keys of visible preferences in built-in preference in xml. */
fun getVisiblePreferenceKeysForMainPage(): List<String>?
fun getVisiblePreferenceKeys(fragmentType: FragmentTypeModel): List<String>?
/** Updates device details fragment layout. */
fun updateLayout()
fun updateLayout(fragmentType: FragmentTypeModel)
}
@OptIn(ExperimentalCoroutinesApi::class)
@@ -79,23 +84,25 @@ class DeviceDetailsFragmentFormatterImpl(
ViewModelProvider(
fragment,
BluetoothDeviceDetailsViewModel.Factory(
fragment.requireActivity().application,
repository,
spatialAudioInteractor,
cachedDevice,
))
.get(BluetoothDeviceDetailsViewModel::class.java)
override fun getVisiblePreferenceKeysForMainPage(): List<String>? = runBlocking {
viewModel
.getItems()
?.filterIsInstance<DeviceSettingConfigItemModel.BuiltinItem>()
?.mapNotNull { it.preferenceKey }
}
override fun getVisiblePreferenceKeys(fragmentType: FragmentTypeModel): List<String>? =
runBlocking {
viewModel
.getItems(fragmentType)
?.filterIsInstance<DeviceSettingConfigItemModel.BuiltinItem>()
?.mapNotNull { it.preferenceKey }
}
/** Updates bluetooth device details fragment layout. */
override fun updateLayout() = runBlocking {
val items = viewModel.getItems() ?: return@runBlocking
val layout = viewModel.getLayout() ?: return@runBlocking
override fun updateLayout(fragmentType: FragmentTypeModel) = runBlocking {
val items = viewModel.getItems(fragmentType) ?: return@runBlocking
val layout = viewModel.getLayout(fragmentType) ?: return@runBlocking
val prefKeyToSettingId =
items
.filterIsInstance<DeviceSettingConfigItemModel.BuiltinItem>()
@@ -124,6 +131,8 @@ class DeviceDetailsFragmentFormatterImpl(
fragment.preferenceScreen.addPreference(pref)
}
}
// TODO(b/343317785): figure out how to remove the foot preference.
fragment.preferenceScreen.addPreference(Preference(context).apply { order = 10000 })
}
@Composable
@@ -132,7 +141,7 @@ class DeviceDetailsFragmentFormatterImpl(
remember(row) {
layout.rows[row].settingIds.flatMapLatest { settingIds ->
if (settingIds.isEmpty()) {
flowOf(emptyList<DeviceSettingModel>())
flowOf(emptyList<DeviceSettingPreferenceModel>())
} else {
combine(
settingIds.map { settingId ->
@@ -150,72 +159,104 @@ class DeviceDetailsFragmentFormatterImpl(
0 -> {}
1 -> {
when (val setting = settings[0]) {
is DeviceSettingModel.ActionSwitchPreference -> {
buildActionSwitchPreference(setting)
is DeviceSettingPreferenceModel.PlainPreference -> {
buildPlainPreference(setting)
}
is DeviceSettingModel.MultiTogglePreference -> {
is DeviceSettingPreferenceModel.SwitchPreference -> {
buildSwitchPreference(setting)
}
is DeviceSettingPreferenceModel.MultiTogglePreference -> {
buildMultiTogglePreference(listOf(setting))
}
null -> {}
else -> {
Log.w(TAG, "Unknown preference type ${setting.id}, skip.")
is DeviceSettingPreferenceModel.FooterPreference -> {
buildFooterPreference(setting)
}
is DeviceSettingPreferenceModel.MoreSettingsPreference -> {
buildMoreSettingsPreference()
}
null -> {}
}
}
else -> {
if (!settings.all { it is DeviceSettingModel.MultiTogglePreference }) {
if (!settings.all { it is DeviceSettingPreferenceModel.MultiTogglePreference }) {
return
}
buildMultiTogglePreference(
settings.filterIsInstance<DeviceSettingModel.MultiTogglePreference>())
settings.filterIsInstance<DeviceSettingPreferenceModel.MultiTogglePreference>())
}
}
}
@Composable
private fun buildMultiTogglePreference(prefs: List<DeviceSettingModel.MultiTogglePreference>) {
private fun buildMultiTogglePreference(
prefs: List<DeviceSettingPreferenceModel.MultiTogglePreference>
) {
MultiTogglePreferenceGroup(prefs)
}
@Composable
private fun buildActionSwitchPreference(model: DeviceSettingModel.ActionSwitchPreference) {
if (model.switchState != null) {
val switchPrefModel =
object : SwitchPreferenceModel {
override val title = model.title
override val summary = { model.summary ?: "" }
override val checked = { model.switchState?.checked }
override val onCheckedChange = { newChecked: Boolean ->
model.updateState?.invoke(
DeviceSettingStateModel.ActionSwitchPreferenceState(newChecked))
Unit
}
override val icon = @Composable { deviceSettingIcon(model) }
private fun buildSwitchPreference(model: DeviceSettingPreferenceModel.SwitchPreference) {
val switchPrefModel =
object : SwitchPreferenceModel {
override val title = model.title
override val summary = { model.summary ?: "" }
override val checked = { model.checked }
override val onCheckedChange = { newChecked: Boolean ->
model.onCheckedChange(newChecked)
}
if (model.intent != null) {
TwoTargetSwitchPreference(switchPrefModel) { context.startActivity(model.intent) }
} else {
SwitchPreference(switchPrefModel)
override val icon = @Composable { deviceSettingIcon(model.icon) }
}
if (model.onPrimaryClick != null) {
TwoTargetSwitchPreference(
switchPrefModel, primaryOnClick = model.onPrimaryClick::invoke)
} else {
SpaPreference(
object : PreferenceModel {
override val title = model.title
override val summary = { model.summary ?: "" }
override val onClick = {
model.intent?.let { context.startActivity(it) }
Unit
}
override val icon = @Composable { deviceSettingIcon(model) }
})
SwitchPreference(switchPrefModel)
}
}
@Composable
private fun deviceSettingIcon(model: DeviceSettingModel.ActionSwitchPreference) {
model.icon?.let { icon ->
Icon(icon, modifier = Modifier.size(SettingsDimension.itemIconSize))
}
private fun buildPlainPreference(model: DeviceSettingPreferenceModel.PlainPreference) {
SpaPreference(
object : PreferenceModel {
override val title = model.title
override val summary = { model.summary ?: "" }
override val onClick = {
model.onClick?.invoke()
Unit
}
override val icon = @Composable { deviceSettingIcon(model.icon) }
})
}
@Composable
fun buildMoreSettingsPreference() {
SpaPreference(
object : PreferenceModel {
override val title =
stringResource(R.string.bluetooth_device_more_settings_preference_title)
override val summary = {
context.getString(R.string.bluetooth_device_more_settings_preference_summary)
}
override val onClick = {
SubSettingLauncher(context)
.setDestination(DeviceDetailsMoreSettingsFragment::class.java.name)
.setSourceMetricsCategory(fragment.getMetricsCategory())
.setArguments(
Bundle().apply { putString(KEY_DEVICE_ADDRESS, cachedDevice.address) })
.launch()
}
override val icon = @Composable { deviceSettingIcon(null) }
})
}
@Composable
fun buildFooterPreference(model: DeviceSettingPreferenceModel.FooterPreference) {
Footer(footerText = model.footerText)
}
@Composable
private fun deviceSettingIcon(icon: DeviceSettingIcon?) {
icon?.let { Icon(it, modifier = Modifier.size(SettingsDimension.itemIconSize)) }
}
private fun getPreferenceKey(settingId: Int) = "DEVICE_SETTING_${settingId}"

View File

@@ -0,0 +1,92 @@
/*
* Copyright (C) 2024 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.settings.bluetooth.ui.view
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothManager
import android.content.Context
import android.os.Bundle
import com.android.settings.R
import com.android.settings.bluetooth.BluetoothDetailsProfilesController
import com.android.settings.bluetooth.Utils
import com.android.settings.bluetooth.ui.model.FragmentTypeModel
import com.android.settings.dashboard.DashboardFragment
import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.settingslib.bluetooth.LocalBluetoothManager
import com.android.settingslib.core.AbstractPreferenceController
import com.android.settingslib.core.lifecycle.LifecycleObserver
class DeviceDetailsMoreSettingsFragment : DashboardFragment() {
private lateinit var formatter: DeviceDetailsFragmentFormatter
private lateinit var localBluetoothManager: LocalBluetoothManager
private lateinit var cachedDevice: CachedBluetoothDevice
// TODO(b/343317785): add metrics category
override fun getMetricsCategory(): Int = 0
override fun getPreferenceScreenResId(): Int {
return R.xml.bluetooth_device_more_settings_fragment
}
override fun addPreferenceController(controller: AbstractPreferenceController) {
val keys: List<String>? =
formatter.getVisiblePreferenceKeys(FragmentTypeModel.DeviceDetailsMoreSettingsFragment)
val lifecycle = settingsLifecycle
if (keys == null || keys.contains(controller.preferenceKey)) {
super.addPreferenceController(controller)
} else if (controller is LifecycleObserver) {
lifecycle.removeObserver((controller as LifecycleObserver))
}
}
private fun getCachedDevice(): CachedBluetoothDevice? {
val bluetoothAddress = arguments?.getString(KEY_DEVICE_ADDRESS) ?: return null
localBluetoothManager = Utils.getLocalBtManager(context) ?: return null
val remoteDevice: BluetoothDevice =
localBluetoothManager.bluetoothAdapter.getRemoteDevice(bluetoothAddress) ?: return null
return Utils.getLocalBtManager(context).cachedDeviceManager.findDevice(remoteDevice)
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
super.onCreatePreferences(savedInstanceState, rootKey)
formatter.updateLayout(FragmentTypeModel.DeviceDetailsMoreSettingsFragment)
}
override fun createPreferenceControllers(context: Context): List<AbstractPreferenceController> {
val bluetoothManager = context.getSystemService(BluetoothManager::class.java)
cachedDevice =
getCachedDevice()
?: run {
finish()
return emptyList()
}
formatter =
featureFactory.bluetoothFeatureProvider.getDeviceDetailsFragmentFormatter(
requireContext(), this, bluetoothManager.adapter, cachedDevice)
return listOf(
BluetoothDetailsProfilesController(
context, this, localBluetoothManager, cachedDevice, settingsLifecycle))
}
override fun getLogTag(): String = TAG
companion object {
const val TAG: String = "DeviceMoreSettingsFrg"
const val KEY_DEVICE_ADDRESS: String = "device_address"
}
}

View File

@@ -16,17 +16,22 @@
package com.android.settings.bluetooth.ui.viewmodel
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import com.android.settings.bluetooth.domain.interactor.SpatialAudioInteractor
import com.android.settings.bluetooth.ui.layout.DeviceSettingLayout
import com.android.settings.bluetooth.ui.layout.DeviceSettingLayoutRow
import com.android.settings.bluetooth.ui.model.DeviceSettingPreferenceModel
import com.android.settings.bluetooth.ui.model.FragmentTypeModel
import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.settingslib.bluetooth.devicesettings.DeviceSettingId
import com.android.settingslib.bluetooth.devicesettings.data.repository.DeviceSettingRepository
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingConfigItemModel
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingModel
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingStateModel
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
@@ -38,30 +43,81 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
class BluetoothDeviceDetailsViewModel(
private val application: Application,
private val deviceSettingRepository: DeviceSettingRepository,
private val spatialAudioInteractor: SpatialAudioInteractor,
private val cachedDevice: CachedBluetoothDevice,
) : ViewModel() {
) : AndroidViewModel(application){
private val items =
viewModelScope.async(Dispatchers.IO, start = CoroutineStart.LAZY) {
deviceSettingRepository.getDeviceSettingsConfig(cachedDevice)
}
suspend fun getItems(): List<DeviceSettingConfigItemModel>? = items.await()?.mainItems
suspend fun getItems(fragment: FragmentTypeModel): List<DeviceSettingConfigItemModel>? =
when (fragment) {
is FragmentTypeModel.DeviceDetailsMainFragment -> items.await()?.mainItems
is FragmentTypeModel.DeviceDetailsMoreSettingsFragment ->
items.await()?.moreSettingsItems
}
fun getDeviceSetting(
cachedDevice: CachedBluetoothDevice,
@DeviceSettingId settingId: Int
): Flow<DeviceSettingModel?> {
): Flow<DeviceSettingPreferenceModel?> {
if (settingId == DeviceSettingId.DEVICE_SETTING_ID_MORE_SETTINGS) {
return flowOf(DeviceSettingPreferenceModel.MoreSettingsPreference(settingId))
}
return when (settingId) {
DeviceSettingId.DEVICE_SETTING_ID_SPATIAL_AUDIO_MULTI_TOGGLE ->
spatialAudioInteractor.getDeviceSetting(cachedDevice)
else -> deviceSettingRepository.getDeviceSetting(cachedDevice, settingId)
}.map { it?.toPreferenceModel() }
}
private fun DeviceSettingModel.toPreferenceModel(): DeviceSettingPreferenceModel? {
return when (this) {
is DeviceSettingModel.ActionSwitchPreference -> {
if (switchState != null) {
DeviceSettingPreferenceModel.SwitchPreference(
id = id,
title = title,
summary = summary,
icon = icon,
checked = switchState?.checked ?: false,
onCheckedChange = { newState ->
updateState?.invoke(
DeviceSettingStateModel.ActionSwitchPreferenceState(newState))
},
onPrimaryClick = { intent?.let { application.startActivity(it) } })
} else {
DeviceSettingPreferenceModel.PlainPreference(
id = id,
title = title,
summary = summary,
icon = icon,
onClick = { intent?.let { application.startActivity(it) } })
}
}
is DeviceSettingModel.FooterPreference ->
DeviceSettingPreferenceModel.FooterPreference(id = id, footerText = footerText)
is DeviceSettingModel.MultiTogglePreference ->
DeviceSettingPreferenceModel.MultiTogglePreference(
id = id,
title = title,
toggles = toggles,
isActive = isActive,
selectedIndex = state.selectedIndex,
isAllowedChangingState = isAllowedChangingState,
onSelectedChange = { newState ->
updateState(DeviceSettingStateModel.MultiTogglePreferenceState(newState))
})
is DeviceSettingModel.Unknown -> null
}
}
suspend fun getLayout(): DeviceSettingLayout? {
val configItems = getItems() ?: return null
suspend fun getLayout(fragment: FragmentTypeModel): DeviceSettingLayout? {
val configItems = getItems(fragment) ?: return null
val idToDeviceSetting =
configItems
.filterIsInstance<DeviceSettingConfigItemModel.AppProvidedItem>()
@@ -80,7 +136,7 @@ class BluetoothDeviceDetailsViewModel(
if (!isXmlPreference && setting == null) {
continue
}
if (setting !is DeviceSettingModel.MultiTogglePreference) {
if (setting !is DeviceSettingPreferenceModel.MultiTogglePreference) {
multiToggleSettingIds = null
positionMapping[i] = listOf(configItem.settingId)
continue
@@ -103,6 +159,7 @@ class BluetoothDeviceDetailsViewModel(
}
class Factory(
private val application: Application,
private val deviceSettingRepository: DeviceSettingRepository,
private val spatialAudioInteractor: SpatialAudioInteractor,
private val cachedDevice: CachedBluetoothDevice,
@@ -110,7 +167,7 @@ class BluetoothDeviceDetailsViewModel(
override fun <T : ViewModel> create(modelClass: Class<T>): T {
@Suppress("UNCHECKED_CAST")
return BluetoothDeviceDetailsViewModel(
deviceSettingRepository, spatialAudioInteractor, cachedDevice)
application, deviceSettingRepository, spatialAudioInteractor, cachedDevice)
as T
}
}