1 /**
<lambda>null2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * ```
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  * ```
10  *
11  * Unless required by applicable law or agreed to in writing, software distributed under the License
12  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
13  * or implied. See the License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 package com.android.healthconnect.controller.dataentries.formatters
17 
18 import android.content.Context
19 import android.health.connect.datatypes.MealType
20 import android.health.connect.datatypes.NutritionRecord
21 import android.health.connect.datatypes.units.Energy
22 import android.health.connect.datatypes.units.Mass
23 import android.icu.text.MessageFormat.*
24 import androidx.annotation.StringRes
25 import com.android.healthconnect.controller.R
26 import com.android.healthconnect.controller.dataentries.formatters.EnergyFormatter.formatEnergyA11yValue
27 import com.android.healthconnect.controller.dataentries.formatters.EnergyFormatter.formatEnergyValue
28 import com.android.healthconnect.controller.dataentries.formatters.MealFormatter.formatMealType
29 import com.android.healthconnect.controller.dataentries.formatters.shared.EntryFormatter
30 import com.android.healthconnect.controller.dataentries.units.UnitPreferences
31 import dagger.hilt.android.qualifiers.ApplicationContext
32 import java.util.StringJoiner
33 import javax.inject.Inject
34 
35 /** Formatter for printing NutritionRecord data. */
36 class NutritionFormatter @Inject constructor(@ApplicationContext private val context: Context) :
37     EntryFormatter<NutritionRecord>(context) {
38 
39     override suspend fun formatValue(
40         record: NutritionRecord,
41         unitPreferences: UnitPreferences
42     ): String {
43         val nutritionData =
44             getAggregations(
45                 record,
46                 { mass ->
47                     val grams = mass.inGrams
48                     format(context.getString(R.string.gram_short_format), mapOf("count" to grams))
49                 },
50                 { energy -> formatEnergyValue(context, energy, unitPreferences) })
51         return nutritionData.ifEmpty { "-" }
52     }
53 
54     override suspend fun formatA11yValue(
55         record: NutritionRecord,
56         unitPreferences: UnitPreferences
57     ): String {
58         val nutritionData =
59             getAggregations(
60                 record,
61                 { mass ->
62                     val grams = mass.inGrams
63                     format(context.getString(R.string.gram_long_format), mapOf("count" to grams))
64                 },
65                 { energy -> formatEnergyA11yValue(context, energy, unitPreferences) })
66         return nutritionData.ifEmpty { "-" }
67     }
68 
69     private fun getAggregations(
70         record: NutritionRecord,
71         formatMass: (mass: Mass) -> String,
72         formatEnergy: (energy: Energy) -> String,
73     ): String {
74         val stringJoiner = StringJoiner("\n")
75         record.mealName?.run { stringJoiner.addAggregation(R.string.meal_name, this) }
76         if (record.mealType != MealType.MEAL_TYPE_UNKNOWN) {
77             stringJoiner.addAggregation(
78                 R.string.mealtype_label, formatMealType(context, record.mealType))
79         }
80         record.biotin?.addAggregation(R.string.biotin, stringJoiner, formatMass)
81         record.caffeine?.addAggregation(R.string.caffeine, stringJoiner, formatMass)
82         record.calcium?.addAggregation(R.string.calcium, stringJoiner, formatMass)
83         record.chloride?.addAggregation(R.string.chloride, stringJoiner, formatMass)
84         record.cholesterol?.addAggregation(R.string.cholesterol, stringJoiner, formatMass)
85         record.chromium?.addAggregation(R.string.chromium, stringJoiner, formatMass)
86         record.copper?.addAggregation(R.string.copper, stringJoiner, formatMass)
87         record.dietaryFiber?.addAggregation(R.string.dietary_fiber, stringJoiner, formatMass)
88         record.energy?.addAggregation(R.string.energy_consumed_total, stringJoiner, formatEnergy)
89         record.energyFromFat?.addAggregation(
90             R.string.energy_consumed_from_fat, stringJoiner, formatEnergy)
91         record.folate?.addAggregation(R.string.folate, stringJoiner, formatMass)
92         record.folicAcid?.addAggregation(R.string.folic_acid, stringJoiner, formatMass)
93         record.iodine?.addAggregation(R.string.iodine, stringJoiner, formatMass)
94         record.iron?.addAggregation(R.string.iron, stringJoiner, formatMass)
95         record.magnesium?.addAggregation(R.string.magnesium, stringJoiner, formatMass)
96         record.manganese?.addAggregation(R.string.manganese, stringJoiner, formatMass)
97         record.molybdenum?.addAggregation(R.string.molybdenum, stringJoiner, formatMass)
98         record.monounsaturatedFat?.addAggregation(
99             R.string.monounsaturated_fat, stringJoiner, formatMass)
100         record.niacin?.addAggregation(R.string.niacin, stringJoiner, formatMass)
101         record.pantothenicAcid?.addAggregation(R.string.pantothenic_acid, stringJoiner, formatMass)
102         record.phosphorus?.addAggregation(R.string.phosphorus, stringJoiner, formatMass)
103         record.polyunsaturatedFat?.addAggregation(
104             R.string.polyunsaturated_fat, stringJoiner, formatMass)
105         record.potassium?.addAggregation(R.string.potassium, stringJoiner, formatMass)
106         record.riboflavin?.addAggregation(R.string.riboflavin, stringJoiner, formatMass)
107         record.saturatedFat?.addAggregation(R.string.saturated_fat, stringJoiner, formatMass)
108         record.selenium?.addAggregation(R.string.selenium, stringJoiner, formatMass)
109         record.sodium?.addAggregation(R.string.sodium, stringJoiner, formatMass)
110         record.sugar?.addAggregation(R.string.sugar, stringJoiner, formatMass)
111         record.thiamin?.addAggregation(R.string.thiamin, stringJoiner, formatMass)
112         record.totalCarbohydrate?.addAggregation(
113             R.string.total_carbohydrate, stringJoiner, formatMass)
114         record.totalFat?.addAggregation(R.string.total_fat, stringJoiner, formatMass)
115         record.transFat?.addAggregation(R.string.trans_fat, stringJoiner, formatMass)
116         record.unsaturatedFat?.addAggregation(R.string.unsaturated_fat, stringJoiner, formatMass)
117         record.vitaminA?.addAggregation(R.string.vitamin_a, stringJoiner, formatMass)
118         record.vitaminB12?.addAggregation(R.string.vitamin_b12, stringJoiner, formatMass)
119         record.vitaminB6?.addAggregation(R.string.vitamin_b6, stringJoiner, formatMass)
120         record.vitaminC?.addAggregation(R.string.vitamin_c, stringJoiner, formatMass)
121         record.vitaminD?.addAggregation(R.string.vitamin_d, stringJoiner, formatMass)
122         record.vitaminE?.addAggregation(R.string.vitamin_e, stringJoiner, formatMass)
123         record.vitaminK?.addAggregation(R.string.vitamin_k, stringJoiner, formatMass)
124         record.zinc?.addAggregation(R.string.zinc, stringJoiner, formatMass)
125 
126         return stringJoiner.toString()
127     }
128 
129     private fun StringJoiner.addAggregation(@StringRes labelRes: Int, value: String) {
130         val label = context.getString(labelRes)
131         add(context.getString(R.string.nutrient_with_value, label, value))
132     }
133 
134     private fun Mass.addAggregation(
135         @StringRes labelRes: Int,
136         stringJoiner: StringJoiner,
137         formatMass: (mass: Mass) -> String
138     ) {
139         stringJoiner.addAggregation(labelRes, formatMass(this))
140     }
141 
142     private fun Energy.addAggregation(
143         @StringRes labelRes: Int,
144         stringJoiner: StringJoiner,
145         formatEnergy: (energy: Energy) -> String
146     ) {
147         stringJoiner.addAggregation(labelRes, formatEnergy(this))
148     }
149 }
150