1 /* <lambda>null2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 */ 17 18 package com.android.customization.picker.grid.domain.interactor 19 20 import com.android.customization.model.CustomizationManager 21 import com.android.customization.picker.grid.data.repository.GridRepository 22 import com.android.customization.picker.grid.shared.model.GridOptionItemModel 23 import com.android.customization.picker.grid.shared.model.GridOptionItemsModel 24 import javax.inject.Provider 25 import kotlinx.coroutines.CoroutineScope 26 import kotlinx.coroutines.flow.Flow 27 import kotlinx.coroutines.flow.SharingStarted 28 import kotlinx.coroutines.flow.emptyFlow 29 import kotlinx.coroutines.flow.flatMapLatest 30 import kotlinx.coroutines.flow.flow 31 import kotlinx.coroutines.flow.map 32 import kotlinx.coroutines.flow.onStart 33 import kotlinx.coroutines.flow.shareIn 34 35 class GridInteractor( 36 private val applicationScope: CoroutineScope, 37 private val repository: GridRepository, 38 private val snapshotRestorer: Provider<GridSnapshotRestorer>, 39 ) { 40 val options: Flow<GridOptionItemsModel> = 41 flow { emit(repository.isAvailable()) } 42 .flatMapLatest { isAvailable -> 43 if (isAvailable) { 44 // this upstream flow tells us each time the options are changed. 45 repository 46 .getOptionChanges() 47 // when we start, we pretend the options _just_ changed. This way, we load 48 // something as soon as possible into the flow so it's ready by the time the 49 // first observer starts to observe. 50 .onStart { emit(Unit) } 51 // each time the options changed, we load them. 52 .map { reload() } 53 // we place the loaded options in a SharedFlow so downstream observers all 54 // share the same flow and don't trigger a new one each time they want to 55 // start observing. 56 .shareIn( 57 scope = applicationScope, 58 started = SharingStarted.WhileSubscribed(), 59 replay = 1, 60 ) 61 } else { 62 emptyFlow() 63 } 64 } 65 66 suspend fun setSelectedOption(model: GridOptionItemModel) { 67 model.onSelected.invoke() 68 } 69 70 suspend fun getSelectedOption(): GridOptionItemModel? { 71 return (repository.getOptions() as? GridOptionItemsModel.Loaded)?.options?.firstOrNull { 72 optionItem -> 73 optionItem.isSelected.value 74 } 75 } 76 77 fun getSelectOptionStateFlow() = repository.getSelectedOption() 78 79 fun clearSelectedOption() = repository.clearSelectedOption() 80 81 fun isSelectedOptionApplied() = repository.isSelectedOptionApplied() 82 83 fun applySelectedOption(callback: CustomizationManager.Callback) { 84 repository.applySelectedOption(callback) 85 } 86 87 private suspend fun reload(): GridOptionItemsModel { 88 val model = repository.getOptions() 89 return if (model is GridOptionItemsModel.Loaded) { 90 GridOptionItemsModel.Loaded( 91 options = 92 model.options.map { option -> 93 GridOptionItemModel( 94 name = option.name, 95 cols = option.cols, 96 rows = option.rows, 97 isSelected = option.isSelected, 98 onSelected = { 99 option.onSelected() 100 snapshotRestorer.get().store(option) 101 }, 102 ) 103 } 104 ) 105 } else { 106 model 107 } 108 } 109 } 110