1 /* <lambda>null2 * Copyright (C) 2022 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.wallpaper.picker.customization.ui.viewmodel 19 20 import android.os.Bundle 21 import androidx.annotation.VisibleForTesting 22 import androidx.lifecycle.AbstractSavedStateViewModelFactory 23 import androidx.lifecycle.SavedStateHandle 24 import androidx.lifecycle.ViewModel 25 import androidx.lifecycle.viewModelScope 26 import androidx.savedstate.SavedStateRegistryOwner 27 import com.android.wallpaper.model.Screen 28 import com.android.wallpaper.module.logging.UserEventLogger 29 import com.android.wallpaper.picker.customization.domain.interactor.WallpaperInteractor 30 import com.android.wallpaper.picker.customization.shared.model.WallpaperDestination 31 import com.android.wallpaper.picker.undo.domain.interactor.UndoInteractor 32 import com.android.wallpaper.picker.undo.ui.viewmodel.UndoViewModel 33 import kotlinx.coroutines.flow.Flow 34 import kotlinx.coroutines.flow.MutableStateFlow 35 import kotlinx.coroutines.flow.asStateFlow 36 import kotlinx.coroutines.flow.map 37 38 /** Models UI state for the customization picker. */ 39 class CustomizationPickerViewModel 40 @VisibleForTesting 41 constructor( 42 undoInteractor: UndoInteractor, 43 wallpaperInteractor: WallpaperInteractor, 44 private val savedStateHandle: SavedStateHandle, 45 private val logger: UserEventLogger, 46 ) : AnimationStateViewModel() { 47 48 val undo: UndoViewModel = 49 UndoViewModel( 50 interactor = undoInteractor, 51 logger = logger, 52 ) 53 54 private val homeWallpaperQuickSwitchViewModel: WallpaperQuickSwitchViewModel = 55 WallpaperQuickSwitchViewModel( 56 interactor = wallpaperInteractor, 57 destination = WallpaperDestination.HOME, 58 coroutineScope = viewModelScope, 59 ) 60 61 private val lockWallpaperQuickSwitchViewModel: WallpaperQuickSwitchViewModel = 62 WallpaperQuickSwitchViewModel( 63 interactor = wallpaperInteractor, 64 destination = WallpaperDestination.LOCK, 65 coroutineScope = viewModelScope, 66 ) 67 68 fun getWallpaperQuickSwitchViewModel(screen: Screen): WallpaperQuickSwitchViewModel { 69 return if (screen == Screen.LOCK_SCREEN) lockWallpaperQuickSwitchViewModel 70 else homeWallpaperQuickSwitchViewModel 71 } 72 73 private val _isOnLockScreen = MutableStateFlow(true) 74 /** Whether we are on the lock screen. If `false`, we are on the home screen. */ 75 val isOnLockScreen: Flow<Boolean> = _isOnLockScreen.asStateFlow() 76 77 /** A view-model for the "lock screen" tab. */ 78 val lockScreenTab: Flow<CustomizationPickerTabViewModel> = 79 isOnLockScreen.map { onLockScreen -> 80 CustomizationPickerTabViewModel( 81 isSelected = onLockScreen, 82 onClicked = 83 if (!onLockScreen) { 84 { 85 _isOnLockScreen.value = true 86 savedStateHandle[KEY_SAVED_STATE_IS_ON_LOCK_SCREEN] = true 87 } 88 } else { 89 null 90 } 91 ) 92 } 93 /** A view-model for the "home screen" tab. */ 94 val homeScreenTab: Flow<CustomizationPickerTabViewModel> = 95 isOnLockScreen.map { onLockScreen -> 96 CustomizationPickerTabViewModel( 97 isSelected = !onLockScreen, 98 onClicked = 99 if (onLockScreen) { 100 { 101 _isOnLockScreen.value = false 102 savedStateHandle[KEY_SAVED_STATE_IS_ON_LOCK_SCREEN] = false 103 } 104 } else { 105 null 106 } 107 ) 108 } 109 110 init { 111 savedStateHandle.get<Boolean>(KEY_SAVED_STATE_IS_ON_LOCK_SCREEN)?.let { 112 _isOnLockScreen.value = it 113 } 114 } 115 116 /** 117 * Sets the initial screen we should be on, unless there's already a selected screen from a 118 * previous saved state, in which case we ignore the passed-in one. 119 */ 120 fun setInitialScreen(onLockScreen: Boolean) { 121 _isOnLockScreen.value = 122 savedStateHandle[KEY_SAVED_STATE_IS_ON_LOCK_SCREEN] 123 ?: run { 124 savedStateHandle[KEY_SAVED_STATE_IS_ON_LOCK_SCREEN] = onLockScreen 125 onLockScreen 126 } 127 } 128 129 companion object { 130 @JvmStatic 131 fun newFactory( 132 owner: SavedStateRegistryOwner, 133 defaultArgs: Bundle? = null, 134 undoInteractor: UndoInteractor, 135 wallpaperInteractor: WallpaperInteractor, 136 logger: UserEventLogger, 137 ): AbstractSavedStateViewModelFactory = 138 object : AbstractSavedStateViewModelFactory(owner, defaultArgs) { 139 @Suppress("UNCHECKED_CAST") 140 override fun <T : ViewModel> create( 141 key: String, 142 modelClass: Class<T>, 143 handle: SavedStateHandle, 144 ): T { 145 return CustomizationPickerViewModel( 146 undoInteractor = undoInteractor, 147 wallpaperInteractor = wallpaperInteractor, 148 savedStateHandle = handle, 149 logger = logger, 150 ) 151 as T 152 } 153 } 154 155 private const val KEY_SAVED_STATE_IS_ON_LOCK_SCREEN = "is_on_lock_screen" 156 } 157 } 158