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.clock.domain.interactor 19 20 import android.text.TextUtils 21 import android.util.Log 22 import com.android.customization.picker.clock.data.repository.ClockPickerRepository 23 import com.android.customization.picker.clock.shared.model.ClockSnapshotModel 24 import com.android.systemui.plugins.clocks.ClockFontAxisSetting 25 import com.android.wallpaper.picker.undo.domain.interactor.SnapshotRestorer 26 import com.android.wallpaper.picker.undo.domain.interactor.SnapshotStore 27 import com.android.wallpaper.picker.undo.shared.model.RestorableSnapshot 28 import javax.inject.Inject 29 import javax.inject.Singleton 30 import kotlinx.coroutines.flow.distinctUntilChanged 31 import kotlinx.coroutines.flow.firstOrNull 32 import kotlinx.coroutines.flow.map 33 import org.json.JSONArray 34 35 /** Handles state restoration for clocks. */ 36 @Singleton 37 class ClockPickerSnapshotRestorer 38 @Inject 39 constructor(private val repository: ClockPickerRepository) : SnapshotRestorer { 40 private var snapshotStore: SnapshotStore = SnapshotStore.NOOP 41 private var originalOption: ClockSnapshotModel? = null 42 43 override suspend fun setUpSnapshotRestorer(store: SnapshotStore): RestorableSnapshot { 44 snapshotStore = store 45 originalOption = 46 ClockSnapshotModel( 47 clockId = 48 repository.selectedClock 49 .map { clock -> clock.clockId } 50 .distinctUntilChanged() 51 .firstOrNull(), 52 clockSize = repository.selectedClockSize.firstOrNull(), 53 colorToneProgress = 54 repository.selectedClock.map { clock -> clock.colorToneProgress }.firstOrNull(), 55 selectedColorId = 56 repository.selectedClock 57 .map { clock -> clock.selectedColorId } 58 .distinctUntilChanged() 59 .firstOrNull(), 60 seedColor = repository.selectedClock.map { clock -> clock.seedColor }.firstOrNull(), 61 axisSettings = 62 repository.selectedClock 63 .map { clock -> clock.fontAxes.map { it.toSetting() } } 64 .firstOrNull(), 65 ) 66 return snapshot(originalOption) 67 } 68 69 override suspend fun restoreToSnapshot(snapshot: RestorableSnapshot) { 70 originalOption?.let { optionToRestore -> 71 if ( 72 TextUtils.isEmpty(optionToRestore.clockId) || 73 optionToRestore.clockId != snapshot.args[KEY_CLOCK_ID] || 74 optionToRestore.clockSize?.toString() != snapshot.args[KEY_CLOCK_SIZE] || 75 optionToRestore.colorToneProgress?.toString() != 76 snapshot.args[KEY_COLOR_TONE_PROGRESS] || 77 optionToRestore.seedColor?.toString() != snapshot.args[KEY_SEED_COLOR] || 78 optionToRestore.selectedColorId != snapshot.args[KEY_COLOR_ID] || 79 (optionToRestore.axisSettings ?: listOf()) != 80 ClockFontAxisSetting.fromJson(JSONArray(snapshot.args[KEY_FONT_AXES])) 81 ) { 82 Log.wtf( 83 TAG, 84 """ Original clock option does not match snapshot option to restore to. The 85 | current implementation doesn't support undo, only a reset back to the 86 | original clock option.""" 87 .trimMargin(), 88 ) 89 } 90 91 optionToRestore.clockSize?.let { repository.setClockSize(it) } 92 optionToRestore.colorToneProgress?.let { 93 repository.setClockColor( 94 selectedColorId = optionToRestore.selectedColorId, 95 colorToneProgress = optionToRestore.colorToneProgress, 96 seedColor = optionToRestore.seedColor, 97 ) 98 } 99 optionToRestore.clockId?.let { repository.setSelectedClock(it) } 100 optionToRestore.axisSettings?.let { repository.setClockFontAxes(it) } 101 } 102 } 103 104 fun storeSnapshot(clockSnapshotModel: ClockSnapshotModel) { 105 snapshotStore.store(snapshot(clockSnapshotModel)) 106 } 107 108 private fun snapshot(clockSnapshotModel: ClockSnapshotModel? = null): RestorableSnapshot { 109 val options = 110 if (clockSnapshotModel == null) emptyMap() 111 else { 112 buildMap { 113 clockSnapshotModel.clockId?.let { put(KEY_CLOCK_ID, it) } 114 clockSnapshotModel.clockSize?.let { put(KEY_CLOCK_SIZE, it.toString()) } 115 clockSnapshotModel.selectedColorId?.let { put(KEY_COLOR_ID, it) } 116 clockSnapshotModel.colorToneProgress?.let { 117 put(KEY_COLOR_TONE_PROGRESS, it.toString()) 118 } 119 clockSnapshotModel.seedColor?.let { put(KEY_SEED_COLOR, it.toString()) } 120 clockSnapshotModel.axisSettings?.let { 121 put(KEY_FONT_AXES, ClockFontAxisSetting.toJson(it).toString()) 122 } 123 } 124 } 125 126 return RestorableSnapshot(options) 127 } 128 129 companion object { 130 private const val TAG = "ClockPickerSnapshotRestorer" 131 private const val KEY_CLOCK_ID = "clock_id" 132 private const val KEY_CLOCK_SIZE = "clock_size" 133 private const val KEY_COLOR_ID = "color_id" 134 private const val KEY_COLOR_TONE_PROGRESS = "color_tone_progress" 135 private const val KEY_SEED_COLOR = "seed_color" 136 private const val KEY_FONT_AXES = "font_axes" 137 } 138 } 139