1/* 2 * Copyright (c) 2024 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 */ 15import deviceManager from '@ohos.distributedHardware.deviceManager'; 16import UIExtensionContentSession from '@ohos.app.ability.UIExtensionContentSession' 17 18let dmClass: deviceManager.DeviceManager | null; 19let TAG = '[DeviceManagerUI:InputPinDialog]==>'; 20const ACTION_CANCEL_PINCODE_INPUT: number = 4; 21const ACTION_DONE_PINCODE_INPUT: number = 5; 22const MSG_PIN_CODE_ERROR: number = 0; 23const MSG_CANCEL_PIN_CODE_INPUT: number = 3; 24const MSG_DOING_AUTH: number = 4; 25const BUTTON_BG_COLOR = 'rgba(255, 255, 255, 0.15)'; 26const TOAST_DURATION_TIME_MS = 1500; 27const MAX_PINCODE_LENGTH = 6; 28 29@Entry 30@Component 31struct Index { 32 @State isTimes: number = 3; 33 @State passwordCircle: string[] = ['', '', '', '', '', '']; 34 @State errorTips: Resource = $r('app.plural.dm_incorrect_code', this.isTimes, this.isTimes); 35 @State @Watch('onChangeInput') input: string = ''; 36 private keyboards: string[][] = [ 37 ['1', '2', '3'], 38 ['4', '5', '6'], 39 ['7', '8', '9'], 40 ['', '0', 'x'], 41 ]; 42 @State isUserInput: boolean = false; 43 @State isUserOperate: boolean = false; 44 45 dialogController: CustomDialogController = new CustomDialogController({ 46 builder: errTips({attemptTimes: this.isTimes, errTips: this.errorTips}), 47 autoCancel: false, 48 alignment: DialogAlignment.Center, 49 customStyle: true, 50 maskColor: $r('sys.color.ohos_id_color_mask_thin'), 51 }); 52 53 aboutToAppear() { 54 if (dmClass) { 55 console.log(TAG + 'deviceManager exist'); 56 return; 57 } 58 deviceManager.createDeviceManager('com.ohos.devicemanagerui.input', 59 (err: Error, dm: deviceManager.DeviceManager) => { 60 if (err) { 61 console.log('createDeviceManager err:' + JSON.stringify(err) + ' --fail:' + '${dm}'); 62 return; 63 } 64 dmClass = dm; 65 dmClass.on('uiStateChange', (data: Record<string, string>) => { 66 console.log('uiStateChange executed, dialog closed' + JSON.stringify(data)); 67 let tmpStr: Record<string, number> = JSON.parse(data.param); 68 let msg: number = tmpStr.uiStateMsg as number; 69 if (msg === MSG_DOING_AUTH) { 70 this.errorTips = $r('app.string.dm_authenticating'); 71 return; 72 } 73 if (msg === MSG_CANCEL_PIN_CODE_INPUT) { 74 this.destruction(); 75 return; 76 } 77 if (msg === MSG_PIN_CODE_ERROR) { 78 this.isTimes--; 79 this.errorTips = $r('app.plural.dm_incorrect_code', this.isTimes, this.isTimes); 80 this.input = ''; 81 this.passwordCircle = ['', '', '', '', '', '']; 82 this.showToast(); 83 } 84 }); 85 }); 86 } 87 88 aboutToDisappear() { 89 console.log(TAG + 'aboutToDisappear begin'); 90 if (dmClass != null) { 91 try { 92 dmClass.off('uiStateChange'); 93 dmClass.release(); 94 } catch (error) { 95 console.log('dmClass release failed'); 96 } 97 dmClass = null; 98 } 99 } 100 101 showToast() { 102 if (this.dialogController) { 103 this.dialogController.open(); 104 setTimeout(() => { 105 this.dialogController.close(); 106 }, TOAST_DURATION_TIME_MS); 107 } 108 } 109 110 onPageHide() { 111 console.log('onPageHide'); 112 if (this.isUserOperate) { 113 console.log('user operate'); 114 return; 115 } 116 this.cancel(); 117 } 118 119 destruction() { 120 console.log(TAG + 'destruction begin'); 121 let session = AppStorage.get<UIExtensionContentSession>('inputSession'); 122 if (session) { 123 session.terminateSelf(); 124 } 125 } 126 127 setUserOperation(operation: number, extra: string) { 128 console.log('setUserOperation: ' + operation); 129 if (dmClass === null) { 130 console.log('setUserOperation: ' + 'dmClass null'); 131 return; 132 } 133 try { 134 this.isUserOperate = true; 135 dmClass.setUserOperation(operation, extra); 136 } catch (error) { 137 console.log('dmClass setUserOperation failed'); 138 } 139 } 140 141 cancel() { 142 console.log('cancle'); 143 if (dmClass) { 144 console.log('deviceManager exist'); 145 } else { 146 console.log('createDeviceManager is null'); 147 return; 148 } 149 console.log('cancle' + ACTION_CANCEL_PINCODE_INPUT); 150 this.setUserOperation(ACTION_CANCEL_PINCODE_INPUT, 'extra'); 151 this.destruction(); 152 } 153 154 confirm() { 155 console.log('confirm'); 156 if (this.input === null || this.input === '') { 157 return; 158 } 159 if (dmClass) { 160 console.log('deviceManager exist'); 161 } else { 162 console.log('createDeviceManager is null'); 163 return; 164 } 165 console.log('confirm' + JSON.stringify(ACTION_DONE_PINCODE_INPUT)); 166 this.setUserOperation(ACTION_DONE_PINCODE_INPUT, this.input); 167 } 168 169 build() { 170 Column() { 171 this.titleBuilder(); 172 this.keyboardMocker(); 173 } 174 .backgroundColor(Color.Black) 175 .height('100%') 176 .width('100%') 177 } 178 179 @Builder 180 keyBuilder(key: string) { 181 GridItem() { 182 Button(key) 183 .backgroundColor(BUTTON_BG_COLOR) 184 .fontColor('#FFFFFF') 185 .fontSize($r('sys.float.ohos_id_text_size_headline6')) 186 .onClick(() => { 187 if (this.input.length >= MAX_PINCODE_LENGTH) { 188 return; 189 } 190 this.input += key.toString(); 191 }) 192 .size({ width: 60, height: 48 }) 193 .margin({ left: 3, top: 2 }) 194 .visibility(key === '' ? Visibility.None : Visibility.Visible) 195 } 196 } 197 198 @Builder 199 processKey(key: string) { 200 if (key === 'x') { 201 this.SymbolDelete(); 202 } else { 203 this.keyBuilder(key); 204 } 205 } 206 207 @Builder 208 keyboardMocker() { 209 Grid() { 210 ForEach(this.keyboards, (keysArr: string[]) => { 211 ForEach(keysArr, (key: string) => { 212 this.processKey(key); 213 }) 214 }) 215 } 216 .width(189) 217 .height(200) 218 .margin({ top: 2 }) 219 } 220 221 @Builder 222 SymbolDelete() { 223 SymbolGlyph($r('sys.symbol.delete_left_fill')) 224 .fontSize('28vp') 225 .renderingStrategy(SymbolRenderingStrategy.MULTIPLE_OPACITY) 226 .fontColor(['#FFFFFF']) 227 .margin({ left: 10, top: 5 }) 228 .onClick(() => { 229 this.input = this.input.slice(0, -1); 230 }) 231 .visibility(this.isUserInput ? Visibility.Visible : Visibility.None) 232 } 233 234 @Builder 235 PinCode() { 236 Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { 237 ForEach(this.passwordCircle, (item:string) => { 238 Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { 239 Text(item) 240 .fontSize($r('sys.float.ohos_id_text_size_sub_title2')) 241 .fontColor('#FFFFFF') 242 .fontWeight(FontWeight.Medium) 243 }.width('7%') 244 .visibility(item === '' ? Visibility.None : Visibility.Visible) 245 }) 246 ForEach(this.passwordCircle, (item: string) => { 247 Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { 248 Column() 249 .width(9) 250 .height(9) 251 .border({ width: 1, color: '#FFFFFF', radius: 9}) 252 .alignItems(HorizontalAlign.Center) 253 }.width('7%') 254 .visibility(item === '' ? Visibility.Visible : Visibility.None) 255 }) 256 } 257 } 258 259 @Builder 260 titleBuilder() { 261 Text($r('app.string.dm_enter_peer_connect_code')) 262 .fontColor('#FFFFFF') 263 .fontSize($r('sys.float.ohos_id_text_size_body2')) 264 .margin({ top: 10 }) 265 .textOverflow({ overflow: TextOverflow.MARQUEE }) 266 .visibility(this.isUserInput ? Visibility.None : Visibility.Visible) 267 .height(19) 268 Stack() { 269 List() { 270 ListItem() { 271 this.PinCode(); 272 } 273 } 274 } 275 .visibility(this.isUserInput ? Visibility.Visible : Visibility.None) 276 .margin({ top: 9 }) 277 .height(20) 278 } 279 280 onChangeInput(changedPropertyName: string) { 281 let length = this.input.length; 282 for (let i = 0; i < MAX_PINCODE_LENGTH; ++i) { 283 if (i < length) { 284 this.passwordCircle[i] = this.input[i]; 285 } else { 286 this.passwordCircle[i] = ''; 287 } 288 } 289 if (length === MAX_PINCODE_LENGTH) { 290 setTimeout(() => { 291 this.setUserOperation(ACTION_DONE_PINCODE_INPUT, this.input); 292 }, 50); 293 } 294 this.isUserInput = true; 295 } 296} 297 298@CustomDialog 299struct errTips { 300 controller?: CustomDialogController; 301 @Link attemptTimes: number; 302 @Link errTips: Resource; 303 build() { 304 Column() { 305 Text(this.errTips) 306 .fontSize(15) 307 .fontColor('#FFFFFF') 308 .textAlign(TextAlign.Center) 309 .backgroundColor('#F2404040') 310 } 311 .justifyContent(FlexAlign.Center) 312 .width(205) 313 .padding({left: 12, right: 12, top: 10, bottom: 10 }) 314 .backgroundColor('#F2404040') 315 .borderRadius(19) 316 } 317}