1/** 2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import prompt from '@system.prompt'; 17import Router from '@system.router'; 18import deviceInfo from '@ohos.deviceInfo'; 19import common from '@ohos.app.ability.common'; 20import PasswordListController from '../controller/password/PasswordSettingController'; 21import LogUtil from '../../../../../../common/utils/src/main/ets/default/baseUtil/LogUtil'; 22import { GlobalContext } from '../../../../../../common/utils/src/main/ets/default/baseUtil/GlobalContext'; 23import ConfigData from '../../../../../../common/utils/src/main/ets/default/baseUtil/ConfigData'; 24import HeadComponent from '../../../../../../common/component/src/main/ets/default/headComponent'; 25import EntryComponent from '../../../../../../common/component/src/main/ets/default/entryComponent'; 26import ResourceUtil from '../../../../../../common/search/src/main/ets/default/common/ResourceUtil'; 27import { PasswordSettingItem } from '../../../../../../common/utils/src/main/ets/default/bean/PasswordSettingItem'; 28 29const deviceTypeInfo = deviceInfo.deviceType; 30 31@Entry 32@Component 33struct PasswordSetting { 34 @State isPhoneOrRK: boolean = false; 35 @State isTouched: boolean = false; 36 @State touchedItem: boolean = false; 37 @State listSpace: string = '10vp'; 38 @State faceAuthFailedMessage: string = ''; 39 private TAG_PAGE = ConfigData.TAG + 'PasswordSetting page '; 40 private mController: PasswordListController = new PasswordListController(); 41 // bind Properties 42 @State private passwordList: PasswordSettingItem[][] = []; 43 private pinChallenge: string = ''; 44 // private Properties 45 private lockUi: boolean = false; // prevent continuous and multiple clicks 46 47 aboutToAppear(): void { 48 if (deviceTypeInfo === 'phone' || deviceTypeInfo === 'default') { 49 this.isPhoneOrRK = true; 50 } else { 51 this.isPhoneOrRK = false; 52 } 53 54 // bind component and initialize 55 this.mController.bindComponent(this) 56 .bindProperties(["passwordList", "pinChallenge"]) 57 .initData() 58 .subscribe(); 59 60 ResourceUtil.getString($r('app.float.distance_10')).then(value => this.listSpace = value); 61 ResourceUtil.getString($r("app.string.face_auth_failed")).then(value => this.faceAuthFailedMessage = value); 62 } 63 64 aboutToDisappear(): void { 65 this.mController.unsubscribe(); 66 } 67 68 onPageShow(): void { 69 this.lockUi = false; 70 this.mController.loadData(); 71 } 72 73 @Builder 74 FaceAuthItem() { 75 Stack() { 76 EntryComponent({ 77 settingIcon: '', 78 settingTitle: $r('app.string.face_recognition'), 79 settingSummary: '', 80 settingValue: '', 81 settingArrow: $r("app.string.ic_settings_arrow").toString(), 82 settingArrowStyle: '', 83 settingUri: '', 84 heights: $r('app.float.password_list_item_height'), 85 fontSize: $r('app.float.password_list_item_title_font_size') 86 }) 87 } 88 .width(ConfigData.WH_100_100) 89 .onClick(() => { 90 if (this.lockUi) { 91 return; 92 } 93 this.lockUi = true; 94 let context = GlobalContext.getContext() 95 .getObject(GlobalContext.globalKeySettingsAbilityContext) as common.UIAbilityContext; 96 context.startAbility({ 97 bundleName: ConfigData.FACEAUTH_BUNDLE_NAME, 98 abilityName: ConfigData.FACEAUTH_ABILITY_NAME 99 }) 100 .then((data) => { 101 LogUtil.info(`${this.TAG_PAGE}, ${ConfigData.FACEAUTH_BUNDLE_NAME} start successful. Data: ${JSON.stringify(data)}`); 102 }) 103 .catch((error: Error) => { 104 prompt.showToast({ 105 message: this.faceAuthFailedMessage, 106 duration: 2000 107 }) 108 LogUtil.error(`${this.TAG_PAGE}, ${ConfigData.FACEAUTH_BUNDLE_NAME} start failed. Cause: ${JSON.stringify(error)}`); 109 }) 110 this.lockUi = false; 111 }) 112 } 113 114 @Builder 115 DisablePasswordItem(item: PasswordSettingItem) { 116 Stack() { 117 EntryComponent({ 118 settingIcon: '', 119 settingTitle: item.settingTitle, 120 settingSummary: '', 121 settingValue: item.settingValue, 122 settingArrow: item.settingArrow?.toString(), 123 settingUri: item.settingUri, 124 settingArrowStyle: '', 125 titleFontColor: $r("app.color.font_color_007DFF"), 126 heights: $r('app.float.password_list_item_height'), 127 fontSize: $r('app.float.font_16') 128 }) 129 } 130 .width(ConfigData.WH_100_100) 131 .onClick(() => { 132 if (this.lockUi) { 133 return; 134 } 135 this.lockUi = true; 136 LogUtil.info(this.TAG_PAGE + ' disable password onclick : item = ' + JSON.stringify(item)); 137 this.showClosePasswordDialog(item); 138 this.lockUi = false; 139 }); 140 } 141 142 @Builder 143 NormalItem(item: PasswordSettingItem) { 144 Stack() { 145 EntryComponent({ 146 settingIcon: '', 147 settingTitle: item.settingTitle, 148 settingSummary: '', 149 settingValue: item.settingValue, 150 settingArrow: item.settingArrow?.toString(), 151 settingArrowStyle: '', 152 settingUri: item.settingUri, 153 heights: $r('app.float.password_list_item_height'), 154 fontSize: $r('app.float.font_16') 155 }) 156 } 157 .width(ConfigData.WH_100_100) 158 .onClick(() => { 159 if (this.lockUi) { 160 return; 161 } 162 this.lockUi = true; 163 LogUtil.info(this.TAG_PAGE + ' item onclick : item = ' + JSON.stringify(item)); 164 this.gotoNextPage(item); 165 this.lockUi = false; 166 }); 167 } 168 169 build() { 170 Column() { 171 GridContainer({ gutter: ConfigData.GRID_CONTAINER_GUTTER_24, margin: ConfigData.GRID_CONTAINER_MARGIN_24 }) { 172 Column() { 173 HeadComponent({ headName: $r('app.string.biometricsAndPassword'), isActive: true }); 174 175 List({ space: this.listSpace }) { 176 ForEach(this.passwordList, (group: PasswordSettingItem[]) => { 177 178 // section title 179 if (group[0].settingIsSectionTitle && group[0].settingShouldDisplay) { 180 ListItem() { 181 Text(group[0].settingTitle) 182 .fontColor($r('sys.color.ohos_id_color_text_secondary')) 183 .fontSize($r("app.float.font_14")) 184 .lineHeight($r("app.float.lineHeight_19")) 185 .textAlign(TextAlign.Start) 186 .margin({ top: $r("app.float.distance_9_5") }) 187 .padding({ left: $r('app.float.distance_12'), right: $r('app.float.distance_12') }) 188 .width(ConfigData.WH_100_100); 189 } 190 } 191 192 ListItem() { 193 List() { 194 // item 0 is section title 195 ForEach(group, (item: PasswordSettingItem, index?: number) => { 196 if (index && index > 0 && item.settingShouldDisplay) { 197 ListItem() { 198 if (item.settingAlias == "face_recognition") { 199 // face recognition item 200 this.FaceAuthItem(); 201 } else if (item.settingAlias == 'password_disable_password') { 202 // disable password item 203 this.DisablePasswordItem(item); 204 } else { 205 // normal item 206 this.NormalItem(item); 207 } 208 } 209 } 210 }); 211 } 212 .padding($r('app.float.distance_4')) 213 .width(ConfigData.WH_100_100) 214 .backgroundColor($r("sys.color.ohos_id_color_foreground_contrary")) 215 .borderRadius($r('app.float.radius_24')) 216 .divider({ 217 strokeWidth: $r('app.float.divider_wh'), 218 color: $r('app.color.color_E3E3E3_grey'), 219 startMargin: $r('app.float.wh_value_15'), 220 endMargin: $r('app.float.wh_value_15') 221 }) 222 } 223 }); 224 } 225 .margin({ top: $r('app.float.wh_value_8') }) 226 } 227 .padding({ 228 left: $r('sys.float.ohos_id_card_margin_start'), 229 right: $r('sys.float.ohos_id_card_margin_end') 230 }) 231 .useSizeType({ 232 sm: { span: 4, offset: 0 }, 233 md: { span: 6, offset: 1 }, 234 lg: { span: 8, offset: 2 } 235 }) 236 } 237 .width(ConfigData.WH_100_100) 238 .height(ConfigData.WH_100_100) 239 } 240 .backgroundColor($r("sys.color.ohos_id_color_sub_background")) 241 .width(ConfigData.WH_100_100) 242 .height(ConfigData.WH_100_100) 243 } 244 245 //------------------------------ Router --------------------------- 246 /** 247 * Go to password page 248 * 249 * @param uri : page uri 250 * @param pageRequestCode : page request code 251 */ 252 gotoNextPage(item: PasswordSettingItem) { 253 if (!item.settingUri) { 254 return; 255 } 256 Router.push({ 257 uri: item.settingUri, 258 params: { 259 'pageRequestCode': item.settingRequestCode, 260 'prevPageUri': 'pages/passwordSetting', 261 'pinChallenge': this.pinChallenge 262 }, 263 }); 264 } 265 266 //------------------------------ Dialog --------------------------- 267 /** 268 * Close password dialog 269 * @param item password setting item 270 */ 271 showClosePasswordDialog(delItem: PasswordSettingItem) { 272 AlertDialog.show({ 273 title: $r("app.string.password_disable_password"), 274 message: $r("app.string.password_disable_prompt"), 275 276 primaryButton: { 277 value: $r('app.string.cancel'), 278 action: () => { 279 LogUtil.info(this.TAG_PAGE + 'ClosePasswordDialog cancel click callback.'); 280 } 281 }, 282 secondaryButton: { 283 value: $r('app.string.disable_'), 284 action: () => { 285 LogUtil.info(this.TAG_PAGE + 'ClosePasswordDialog disable click callback.'); 286 this.gotoNextPage(delItem); 287 } 288 }, 289 cancel: () => { 290 LogUtil.info(this.TAG_PAGE + 'ClosePasswordDialog Closed callbacks'); 291 }, 292 autoCancel: true, 293 alignment: this.isPhoneOrRK ? DialogAlignment.Bottom : DialogAlignment.Center, 294 offset: ({ dx: 0, dy: this.isPhoneOrRK ? '-24dp' : 0 }) 295 }) 296 } 297}