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