1 /*
2  * Copyright (C) 2024 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 package com.android.systemui.qs.tiles.impl.night.ui
18 
19 import android.content.res.Resources
20 import android.service.quicksettings.Tile
21 import android.text.TextUtils
22 import androidx.annotation.StringRes
23 import com.android.systemui.accessibility.qs.QSAccessibilityModule
24 import com.android.systemui.common.shared.model.Icon
25 import com.android.systemui.dagger.qualifiers.Main
26 import com.android.systemui.qs.pipeline.shared.TileSpec
27 import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper
28 import com.android.systemui.qs.tiles.base.logging.QSTileLogger
29 import com.android.systemui.qs.tiles.impl.night.domain.model.NightDisplayTileModel
30 import com.android.systemui.qs.tiles.viewmodel.QSTileConfig
31 import com.android.systemui.qs.tiles.viewmodel.QSTileState
32 import com.android.systemui.res.R
33 import java.time.DateTimeException
34 import java.time.LocalTime
35 import java.time.format.DateTimeFormatter
36 import javax.inject.Inject
37 
38 /** Maps [NightDisplayTileModel] to [QSTileState]. */
39 class NightDisplayTileMapper
40 @Inject
41 constructor(
42     @Main private val resources: Resources,
43     private val theme: Resources.Theme,
44     private val logger: QSTileLogger,
45 ) : QSTileDataToStateMapper<NightDisplayTileModel> {
mapnull46     override fun map(config: QSTileConfig, data: NightDisplayTileModel): QSTileState =
47         QSTileState.build(resources, theme, config.uiConfig) {
48             label = resources.getString(R.string.quick_settings_night_display_label)
49             supportedActions =
50                 setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK)
51             sideViewIcon = QSTileState.SideViewIcon.None
52 
53             if (data.isActivated) {
54                 activationState = QSTileState.ActivationState.ACTIVE
55                 iconRes = R.drawable.qs_nightlight_icon_on
56             } else {
57                 activationState = QSTileState.ActivationState.INACTIVE
58                 iconRes = R.drawable.qs_nightlight_icon_off
59             }
60             val loadedIcon =
61                 Icon.Loaded(resources.getDrawable(iconRes!!, theme), contentDescription = null)
62             icon = { loadedIcon }
63 
64             secondaryLabel = getSecondaryLabel(data, resources)
65 
66             contentDescription =
67                 if (TextUtils.isEmpty(secondaryLabel)) label
68                 else TextUtils.concat(label, ", ", secondaryLabel)
69         }
70 
getSecondaryLabelnull71     private fun getSecondaryLabel(
72         data: NightDisplayTileModel,
73         resources: Resources
74     ): CharSequence? {
75         when (data) {
76             is NightDisplayTileModel.AutoModeTwilight -> {
77                 if (!data.isLocationEnabled) {
78                     return null
79                 } else {
80                     return resources.getString(
81                         if (data.isActivated)
82                             R.string.quick_settings_night_secondary_label_until_sunrise
83                         else R.string.quick_settings_night_secondary_label_on_at_sunset
84                     )
85                 }
86             }
87             is NightDisplayTileModel.AutoModeOff -> {
88                 val subtitleArray = resources.getStringArray(R.array.tile_states_night)
89                 return subtitleArray[
90                     if (data.isActivated) Tile.STATE_ACTIVE else Tile.STATE_INACTIVE]
91             }
92             is NightDisplayTileModel.AutoModeCustom -> {
93                 // User-specified time, approximated to the nearest hour.
94                 @StringRes val toggleTimeStringRes: Int
95                 val toggleTime: LocalTime
96                 if (data.isActivated) {
97                     toggleTime = data.endTime ?: return null
98                     toggleTimeStringRes = R.string.quick_settings_secondary_label_until
99                 } else {
100                     toggleTime = data.startTime ?: return null
101                     toggleTimeStringRes = R.string.quick_settings_night_secondary_label_on_at
102                 }
103 
104                 try {
105                     val formatter = if (data.is24HourFormat) formatter24Hour else formatter12Hour
106                     val formatArg = formatter.format(toggleTime)
107                     return resources.getString(toggleTimeStringRes, formatArg)
108                 } catch (exception: DateTimeException) {
109                     logger.logWarning(spec, exception.message.toString())
110                     return null
111                 }
112             }
113         }
114     }
115 
116     private companion object {
117         val formatter12Hour: DateTimeFormatter = DateTimeFormatter.ofPattern("hh:mm a")
118         val formatter24Hour: DateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm")
119         val spec = TileSpec.create(QSAccessibilityModule.NIGHT_DISPLAY_TILE_SPEC)
120     }
121 }
122