1 /* <lambda>null2 * 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 package com.android.healthconnect.controller.selectabledeletion 17 18 import android.app.Dialog 19 import android.os.Bundle 20 import android.view.View 21 import android.widget.CheckBox 22 import android.widget.ImageView 23 import android.widget.TextView 24 import androidx.fragment.app.DialogFragment 25 import androidx.fragment.app.activityViewModels 26 import androidx.fragment.app.setFragmentResult 27 import com.android.healthconnect.controller.R 28 import com.android.healthconnect.controller.data.entries.datenavigation.DateNavigationPeriod 29 import com.android.healthconnect.controller.selectabledeletion.DeletionConstants.CONFIRMATION_KEY 30 import com.android.healthconnect.controller.shared.dialog.AlertDialogBuilder 31 import com.android.healthconnect.controller.utils.AttributeResolver 32 import com.android.healthconnect.controller.utils.LocalDateTimeFormatter 33 import com.android.healthconnect.controller.utils.TimeSource 34 import com.android.healthconnect.controller.utils.formatDateTimeForTimePeriod 35 import com.android.healthconnect.controller.utils.logging.DeletionDialogConfirmationElement 36 import com.android.settingslib.widget.SettingsThemeHelper 37 import dagger.hilt.android.AndroidEntryPoint 38 import javax.inject.Inject 39 40 @AndroidEntryPoint(DialogFragment::class) 41 class DeletionConfirmationDialogFragment : Hilt_DeletionConfirmationDialogFragment() { 42 @Inject lateinit var timeSource: TimeSource 43 private val viewModel: DeletionViewModel by activityViewModels() 44 // TODO (b/384028690) replace after pagination implementation 45 private val PAGE_SIZE = 1000 46 47 override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { 48 val view: View = 49 layoutInflater.inflate( 50 if (SettingsThemeHelper.isExpressiveTheme(requireContext())) 51 R.layout.dialog_layout_expressive 52 else R.layout.dialog_layout_legacy, 53 null, 54 ) 55 val title: TextView = view.findViewById(R.id.dialog_title) 56 val message: TextView = view.findViewById(R.id.dialog_custom_message) 57 val icon: ImageView = view.findViewById(R.id.dialog_icon) 58 val checkbox: CheckBox = view.findViewById(R.id.dialog_checkbox) 59 val iconDrawable = AttributeResolver.getNullableDrawable(view.context, R.attr.deleteIcon) 60 61 title.text = buildTitle() 62 message.setText(R.string.deletion_confirmation_dialog_body) 63 iconDrawable?.let { 64 icon.setImageDrawable(it) 65 icon.visibility = View.VISIBLE 66 } 67 68 setupCheckbox(checkbox) 69 70 val alertDialogBuilder = 71 AlertDialogBuilder( 72 this, 73 DeletionDialogConfirmationElement.DELETION_DIALOG_CONFIRMATION_CONTAINER, 74 ) 75 .setView(view) 76 .setPositiveButton( 77 R.string.confirming_question_delete_button, 78 DeletionDialogConfirmationElement.DELETION_DIALOG_CONFIRMATION_DELETE_BUTTON, 79 ) { _, _ -> 80 viewModel.removePermissions = checkbox.isChecked 81 setFragmentResult(CONFIRMATION_KEY, Bundle()) 82 } 83 .setNeutralButton( 84 android.R.string.cancel, 85 DeletionDialogConfirmationElement.DELETION_DIALOG_CONFIRMATION_CANCEL_BUTTON, 86 ) 87 88 return alertDialogBuilder.create() 89 } 90 91 private fun setupCheckbox(checkBox: CheckBox) { 92 val deletionType = viewModel.getDeletionType() 93 if (deletionType is DeletionType.DeleteHealthPermissionTypesFromApp) { 94 if (deletionType.healthPermissionTypes.size == deletionType.totalPermissionTypes) { 95 checkBox.visibility = View.VISIBLE 96 } else { 97 checkBox.visibility = View.GONE 98 } 99 val appName = deletionType.appName 100 checkBox.text = 101 getString(R.string.confirming_question_app_remove_all_permissions, appName) 102 } else { 103 checkBox.visibility = View.GONE 104 } 105 } 106 107 private fun buildTitle(): String { 108 return when (val deletionType = viewModel.getDeletionType()) { 109 is DeletionType.DeleteHealthPermissionTypes -> 110 if (deletionType.healthPermissionTypes.size < deletionType.totalPermissionTypes) { 111 getString(R.string.some_data_selected_deletion_confirmation_dialog) 112 } else { 113 getString(R.string.all_data_selected_deletion_confirmation_dialog) 114 } 115 is DeletionType.DeleteHealthPermissionTypesFromApp -> { 116 val appName = deletionType.appName 117 if (deletionType.healthPermissionTypes.size < deletionType.totalPermissionTypes) { 118 getString(R.string.some_app_data_selected_deletion_confirmation_dialog, appName) 119 } else { 120 getString(R.string.all_app_data_selected_deletion_confirmation_dialog, appName) 121 } 122 } 123 is DeletionType.DeleteEntries -> { 124 val deletionMapSize = deletionType.idsToDataTypes.size 125 if (deletionMapSize == 1) { 126 return getString(R.string.one_entry_selected_deletion_confirmation_dialog) 127 } 128 val selectedPeriod = deletionType.period 129 val startTime = deletionType.startTime 130 val displayString = 131 formatDateTimeForTimePeriod( 132 startTime, 133 selectedPeriod, 134 LocalDateTimeFormatter(requireContext()), 135 timeSource, 136 false, 137 ) 138 if (selectedPeriod == DateNavigationPeriod.PERIOD_DAY) { 139 if ( 140 deletionMapSize < deletionType.totalEntries || deletionMapSize == PAGE_SIZE 141 ) { 142 getString( 143 R.string.some_entries_selected_day_deletion_confirmation_dialog, 144 displayString, 145 ) 146 } else { 147 getString( 148 R.string.all_entries_selected_day_deletion_confirmation_dialog, 149 displayString, 150 ) 151 } 152 } else if (selectedPeriod == DateNavigationPeriod.PERIOD_WEEK) { 153 if ( 154 deletionMapSize < deletionType.totalEntries || deletionMapSize == PAGE_SIZE 155 ) { 156 getString( 157 R.string.some_entries_selected_week_deletion_confirmation_dialog, 158 displayString, 159 ) 160 } else { 161 getString( 162 R.string.all_entries_selected_week_deletion_confirmation_dialog, 163 displayString, 164 ) 165 } 166 } else { 167 if ( 168 deletionMapSize < deletionType.totalEntries || deletionMapSize == PAGE_SIZE 169 ) { 170 getString( 171 R.string.some_entries_selected_month_deletion_confirmation_dialog, 172 displayString, 173 ) 174 } else { 175 getString( 176 R.string.all_entries_selected_month_deletion_confirmation_dialog, 177 displayString, 178 ) 179 } 180 } 181 } 182 is DeletionType.DeleteEntriesFromApp -> { 183 val deletionMapSize = deletionType.idsToDataTypes.size 184 val appName = deletionType.appName 185 if (deletionMapSize == 1) { 186 return getString( 187 R.string.one_app_entry_selected_deletion_confirmation_dialog, 188 appName, 189 ) 190 } 191 val selectedPeriod = deletionType.period 192 val startTime = deletionType.startTime 193 val displayString = 194 formatDateTimeForTimePeriod( 195 startTime, 196 selectedPeriod, 197 LocalDateTimeFormatter(requireContext()), 198 timeSource, 199 false, 200 ) 201 202 if (selectedPeriod == DateNavigationPeriod.PERIOD_DAY) { 203 if ( 204 deletionMapSize < deletionType.totalEntries || deletionMapSize == PAGE_SIZE 205 ) { 206 getString( 207 R.string.some_app_entries_selected_day_deletion_confirmation_dialog, 208 appName, 209 displayString, 210 ) 211 } else { 212 getString( 213 R.string.all_app_entries_selected_day_deletion_confirmation_dialog, 214 appName, 215 displayString, 216 ) 217 } 218 } else if (selectedPeriod == DateNavigationPeriod.PERIOD_WEEK) { 219 if ( 220 deletionMapSize < deletionType.totalEntries || deletionMapSize == PAGE_SIZE 221 ) { 222 getString( 223 R.string.some_app_entries_selected_week_deletion_confirmation_dialog, 224 appName, 225 displayString, 226 ) 227 } else { 228 getString( 229 R.string.all_app_entries_selected_week_deletion_confirmation_dialog, 230 appName, 231 displayString, 232 ) 233 } 234 } else { 235 if ( 236 deletionMapSize < deletionType.totalEntries || deletionMapSize == PAGE_SIZE 237 ) { 238 getString( 239 R.string.some_app_entries_selected_month_deletion_confirmation_dialog, 240 appName, 241 displayString, 242 ) 243 } else { 244 getString( 245 R.string.all_app_entries_selected_month_deletion_confirmation_dialog, 246 appName, 247 displayString, 248 ) 249 } 250 } 251 } 252 is DeletionType.DeleteAppData -> { 253 val appName = deletionType.appName 254 getString(R.string.all_app_data_selected_deletion_confirmation_dialog, appName) 255 } 256 is DeletionType.DeleteInactiveAppData -> { 257 val appName = deletionType.appName 258 val healthPermissionType = 259 getString(deletionType.healthPermissionType.lowerCaseLabel()) 260 getString( 261 R.string.inactive_app_data_selected_deletion_confirmation_dialog, 262 healthPermissionType, 263 appName, 264 ) 265 } 266 } 267 } 268 269 companion object { 270 const val TAG = "NewDeletionConfirmationDialog" 271 } 272 } 273