Rearrange bluetooth device details fragment according to config

BUG: 343317785
Test: atest DeviceDetailsFragmentFormatterTest
Flag: com.android.settings.flags.enable_bluetooth_device_details_polish
Change-Id: I440f85b2c402920e851915ff56fa7b3f5356e807
This commit is contained in:
Haijie Hong
2024-08-09 14:58:10 +08:00
parent 2a01b356ae
commit 41f7c222b6
13 changed files with 949 additions and 21 deletions

View File

@@ -0,0 +1,107 @@
/*
* 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.viewmodel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import com.android.settings.bluetooth.ui.layout.DeviceSettingLayout
import com.android.settings.bluetooth.ui.layout.DeviceSettingLayoutRow
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 kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
class BluetoothDeviceDetailsViewModel(
private val deviceSettingRepository: DeviceSettingRepository,
private val cachedDevice: CachedBluetoothDevice,
) : ViewModel() {
private val items =
viewModelScope.async(Dispatchers.IO, start = CoroutineStart.LAZY) {
deviceSettingRepository.getDeviceSettingsConfig(cachedDevice)
}
suspend fun getItems(): List<DeviceSettingConfigItemModel>? = items.await()?.mainItems
fun getDeviceSetting(cachedDevice: CachedBluetoothDevice, @DeviceSettingId settingId: Int) =
deviceSettingRepository.getDeviceSetting(cachedDevice, settingId)
suspend fun getLayout(): DeviceSettingLayout? {
val configItems = getItems() ?: return null
val idToDeviceSetting =
configItems
.filterIsInstance<DeviceSettingConfigItemModel.AppProvidedItem>()
.associateBy({ it.settingId }, { getDeviceSetting(cachedDevice, it.settingId) })
val configDeviceSetting =
configItems.map { idToDeviceSetting[it.settingId] ?: flowOf(null) }
val positionToSettingIds =
combine(configDeviceSetting) { settings ->
val positionMapping = mutableMapOf<Int, List<Int>>()
var multiToggleSettingIds: MutableList<Int>? = null
for (i in settings.indices) {
val configItem = configItems[i]
val setting = settings[i]
val isXmlPreference = configItem is DeviceSettingConfigItemModel.BuiltinItem
if (!isXmlPreference && setting == null) {
continue
}
if (setting !is DeviceSettingModel.MultiTogglePreference) {
multiToggleSettingIds = null
positionMapping[i] = listOf(configItem.settingId)
continue
}
if (multiToggleSettingIds != null) {
multiToggleSettingIds.add(setting.id)
} else {
multiToggleSettingIds = mutableListOf(setting.id)
positionMapping[i] = multiToggleSettingIds
}
}
positionMapping
}
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), initialValue = mapOf())
return DeviceSettingLayout(
configItems.indices.map { idx ->
DeviceSettingLayoutRow(positionToSettingIds.map { it[idx] ?: emptyList() })
})
}
class Factory(
private val deviceSettingRepository: DeviceSettingRepository,
private val cachedDevice: CachedBluetoothDevice,
) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
@Suppress("UNCHECKED_CAST")
return BluetoothDeviceDetailsViewModel(deviceSettingRepository, cachedDevice) as T
}
}
companion object {
private const val TAG = "BluetoothDeviceDetailsViewModel"
}
}