• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 Router from '@system.router';
17import deviceInfo from '@ohos.deviceInfo';
18import InputMethod from '@ohos.inputMethod';
19import { PinSubType } from '../model/passwordImpl/PasswordModel';
20import PasswordInputController from '../controller/password/PasswordInputController';
21import LogUtil from '../../../../../../common/utils/src/main/ets/default/baseUtil/LogUtil';
22import Log from '../../../../../../common/utils/src/main/ets/default/baseUtil/LogDecorator';
23import ConfigData from '../../../../../../common/utils/src/main/ets/default/baseUtil/ConfigData';
24import HeadComponent from '../../../../../../common/component/src/main/ets/default/headComponent';
25import { RadioListItem } from '../../../../../../common/utils/src/main/ets/default/bean/RadioListItem';
26import RadioListComponent from '../../../../../../common/component/src/main/ets/default/radioListComponent';
27
28const deviceTypeInfo = deviceInfo.deviceType;
29const TAG = ConfigData.TAG + 'PasswdSetting.PasswdInput -> ';
30
31@Entry
32@Component
33struct PasswordInput {
34  private TAG_PAGE = ConfigData.TAG + 'PasswordInput page ';
35  private mController: PasswordInputController = new PasswordInputController();
36
37  // bind Properties
38  @State @Watch("clearViewData")
39  private isInputFirstTime: boolean = true;
40  @State @Watch("clearViewData")
41  private passwordType: number = -1;
42//  private password: string = '';
43  @State password: string = '';
44  @State passwordCircle: string[]= ["", "", "", "", "", ""];
45
46  // private Properties
47  private pageRequestCode: number = -1;
48  private prevPageUri: string = '';
49  private pinChallenge: string = '';
50  private pinToken: string = '';
51  @State private pageTitle: Resource = $r("app.string.endTextEmpty");
52  @State private inputMessage: Resource = $r("app.string.endTextEmpty");
53  @State private unlockMethodList: RadioListItem[] = [];
54  @State private buttonVisibility: Visibility = Visibility.Visible;
55  @State isTouchedLeft: boolean = false;
56  @State isTouchedRight: boolean = false;
57  @State isFocused: boolean = false;
58
59  // handler
60  private passwordOnChangeHandler: (value: string) => void = () => {};
61  private okOnClickHandler: (event?: ClickEvent) => void = () => {};
62  private unlockMethodChosenHandler: (value: number) => void = () => {};
63
64  //dialog
65  private chooseUnlockMethodDialog: CustomDialogController | null = new CustomDialogController({
66    builder: chooseUnlockMethodDialog({
67      dialogTitle: $r('app.string.password_change_unlock_method'),
68      dataList: this.unlockMethodList,
69      checkedValue: this.passwordType.toString(),
70      chosenAction: (value) => {
71        this.unlockMethodChosenHandler(value);
72      }
73    }),
74    autoCancel: true,
75    alignment: deviceTypeInfo === 'phone' || deviceTypeInfo === 'default' ? DialogAlignment.Bottom : DialogAlignment.Center,
76    offset: ({ dx: 0, dy: deviceTypeInfo === 'phone' || deviceTypeInfo === 'default' ? '-24dp' : 0 })
77  });
78
79  aboutToAppear(): void {
80    this.getRouterParam();
81
82    // bind event handlers
83    this.passwordOnChangeHandler = (value: string):void => this.mController.passwordOnChange(value);
84    this.okOnClickHandler = ():void => this.mController.inputFinish();
85    this.unlockMethodChosenHandler = (value: number):void => this.mController.changePasswordType(value);
86
87    // bind component and initialize
88    this.mController.bindComponent(this)
89      .bindProperties(["passwordType", "isInputFirstTime", "password", "pinToken", "passwordCircle"])
90      .initData()
91      .subscribe();
92
93    this.updateView();
94  }
95
96  aboutToDisappear(): void {
97    this.mController.unsubscribe();
98    this.chooseUnlockMethodDialog = null;
99  }
100
101  /**
102   * Get the params from router
103   */
104  getRouterParam() {
105    let param = Router.getParams()
106    if (!param) {
107      return;
108    }
109    this.pageRequestCode = param.pageRequestCode as number;
110    this.prevPageUri = param.prevPageUri as string;
111    this.pinChallenge = param.pinChallenge as string;
112    this.pinToken = param.pinToken as string;
113    this.passwordType = param.passwordType as number;
114  }
115
116  build() {
117    Column() {
118      GridContainer({ gutter: ConfigData.GRID_CONTAINER_GUTTER_24, margin: ConfigData.GRID_CONTAINER_MARGIN_24 }) {
119        Column() {
120          // head
121          HeadComponent({ headName: this.pageTitle, isActive: true });
122
123          Column() {
124            // input message
125            Text(this.inputMessage)
126              .fontSize($r('sys.float.ohos_id_text_size_sub_title2'))
127              .fontWeight(FontWeight.Medium)
128              .fontColor($r("sys.color.ohos_id_color_primary"))
129              .margin({ top: $r("sys.float.ohos_id_default_padding_top") })
130              .align((this.passwordType == PinSubType.PIN_MIXED) ? Alignment.Start : Alignment.Center)
131
132            // input password
133            if (this.passwordType == PinSubType.PIN_SIX) {
134              Row() {
135                Stack() {
136                  TextInput({ placeholder: '', text: this.password })
137                    .height($r('app.float.distance_36'))
138                    .width($r('app.float.wh_192'))
139                    .opacity(0)
140                    .fontColor(('rgba(0,0,0,0)'))
141                    .backgroundColor(('rgba(0,0,0,0)'))
142                    .caretColor(('rgba(0,0,0,0)'))
143                    .maxLength(6)
144                    .margin({bottom:$r('app.float.wh_value_8')})
145                    .onChange((value: string) => {
146                      this.password = value;
147                      if (value.length > 6) {
148                        return;
149                      }
150                      let length = value.length;
151                      for (let i = 0;i < 6; i++) {
152                        if (i < length) {
153                          this.passwordCircle[i] = value.charAt(i);
154                        } else {
155                          this.passwordCircle[i] = '';
156                        }
157                      }
158                      this.passwordOnChangeHandler(value);
159                    })
160                    .onSubmit((enterKey) => {
161                      InputMethod.getInputMethodController().stopInput()
162                        .then((ret) => {
163                          LogUtil.debug(`${ConfigData.TAG}, enterType: ${enterKey}, stopInput: ${ret}`);
164                        })
165                    });
166
167                  List({ space: 24 }) {
168                    ForEach(this.passwordCircle, (item: string) => {
169                      ListItem() {
170                        Column()
171                          .width($r('app.float.wh_value_12'))
172                          .height($r('app.float.wh_value_12'))
173                          .backgroundColor(item === '' ? 'white' : 'black')
174                          .border({ width: 1, color: 'black', radius: 12 })
175                          .margin({ top: $r('app.float.wh_value_12') })
176                      }
177                    })
178                  }
179                  .hitTestBehavior(HitTestMode.Transparent)
180                  .listDirection(Axis.Horizontal)
181                }
182                .margin({ top: $r('app.float.wh_value_20'),bottom:$r('app.float.wh_value_12') })
183                .width(ConfigData.WH_100_100)
184                .height($r("app.float.wh_value_32"))
185              }
186            } else {
187              Column() {
188                TextInput({ placeholder: '', text: this.password })
189                  .width(ConfigData.WH_100_100)
190                  .height(ConfigData.WH_100_100)
191                  .placeholderFont({
192                    size: $r("app.float.font_18"),
193                    weight: FontWeight.Normal,
194                    style: FontStyle.Normal
195                  })
196                  .type(InputType.Password)
197                  .enterKeyType(EnterKeyType.Done)
198                  .caretColor($r('sys.color.ohos_id_color_text_primary_activated'))
199                  .borderRadius(0)
200                  .layoutWeight(ConfigData.LAYOUT_WEIGHT_1)
201                  .backgroundColor($r('app.color.color_00000000_transparent'))
202                  .onChange(this.passwordOnChangeHandler)
203                  .onSubmit((enterKey) => {
204                    InputMethod.getInputMethodController().stopInput()
205                      .then((ret) => {
206                        LogUtil.debug(`${ConfigData.TAG}, enterType: ${enterKey}, stopInput: ${ret}`);
207                      });
208                  })
209                  .onFocus(() => {
210                    LogUtil.info(TAG + "text input is focused");
211                    this.isFocused = true;
212                  })
213
214                Divider()
215              }
216              .margin({ top: $r('app.float.wh_value_32') })
217              .height($r("app.float.wh_value_48"))
218              .padding({
219                left: $r('sys.float.ohos_id_card_margin_start'),
220                right: $r('sys.float.ohos_id_card_margin_end'),
221                top: $r("app.float.distance_8"),
222                bottom: $r("app.float.distance_6") })
223            }
224
225            CheckText();
226
227            // change unlock method
228            Button({ type: ButtonType.Normal, stateEffect: true }) {
229              Text($r('app.string.password_change_unlock_method'))
230                .fontSize($r('sys.float.ohos_id_text_size_button1'))
231                .fontColor($r('sys.color.ohos_id_color_text_primary_activated'))
232                .fontWeight(FontWeight.Medium)
233                .align(Alignment.Center)
234                .alignSelf(ItemAlign.Center)
235                .textAlign(TextAlign.Center)
236                .visibility(this.isInputFirstTime ? Visibility.Visible : Visibility.Hidden)
237            }
238            .backgroundColor("rgba(0,0,0,0)")
239            .onClick(() => {
240              this.chooseUnlockMethodDialog?.open();
241            })
242          }
243
244          // button
245          Flex({ justifyContent: FlexAlign.SpaceBetween }) {
246            Row() {
247              Button({ type: ButtonType.Capsule, stateEffect: true }) {
248                Text($r('app.string.cancel'))
249                  .fontWeight(FontWeight.Medium)
250                  .fontSize($r('app.float.application_button_subtitle_size'))
251                  .lineHeight($r('app.float.wh_value_22'))
252                  .fontColor($r('app.color.font_color_007DFF'))
253                  .height($r('app.float.application_button_height'))
254                  .textAlign(TextAlign.Center)
255              }
256              .layoutWeight(ConfigData.LAYOUT_WEIGHT_1)
257              .backgroundColor(!this.isTouchedLeft ? $r("sys.color.ohos_id_color_button_normal") : $r("sys.color.ohos_id_color_foreground_contrary"))
258              .onTouch((event?: TouchEvent) => {
259                if (event?.type === TouchType.Down) {
260                  this.isTouchedLeft = true;
261                }
262
263                if (event?.type === TouchType.Up) {
264                  this.isTouchedLeft = false;
265                }
266              })
267              .onClick(() => {
268                Router.back();
269              })
270
271              Column()
272                .width( $r('app.float.distance_12'))
273                .height($r('app.float.application_button_height'))
274
275              Button({ type: ButtonType.Capsule, stateEffect: true }) {
276                Text(this.isInputFirstTime ? $r('app.string.continue_') : $r('app.string.confirm'))
277                  .fontWeight(FontWeight.Medium)
278                  .fontSize($r('app.float.application_button_subtitle_size'))
279                  .lineHeight($r('app.float.wh_value_22'))
280                  .fontColor($r('app.color.font_color_007DFF'))
281                  .height($r('app.float.application_button_height'))
282                  .textAlign(TextAlign.Center)
283              }
284              .layoutWeight(ConfigData.LAYOUT_WEIGHT_1)
285              .backgroundColor(!this.isTouchedRight ? $r("sys.color.ohos_id_color_button_normal") : $r("sys.color.ohos_id_color_foreground_contrary"))
286              .onTouch((event?: TouchEvent) => {
287                if (event?.type === TouchType.Down) {
288                  this.isTouchedRight = true;
289                }
290
291                if (event?.type === TouchType.Up) {
292                  this.isTouchedRight = false;
293                  this.isFocused = true;
294                }
295              })
296              .onClick(this.okOnClickHandler)
297            }
298            .alignItems(this.isFocused === false ? VerticalAlign.Bottom : VerticalAlign.Top)
299            .height(this.passwordType == PinSubType.PIN_MIXED && (deviceTypeInfo === 'phone' || deviceTypeInfo === 'default') ? "58%" : "66%")
300            .padding(this.isFocused === false ? { bottom: 24 } : { top: (this.passwordType == PinSubType.PIN_MIXED ? "14%" : "16%") })
301          }
302          .width(ConfigData.WH_100_100)
303          .visibility(this.buttonVisibility)
304        }
305        .useSizeType({
306          sm: { span: 4, offset: 0 },
307          md: { span: 6, offset: 1 },
308          lg: { span: 8, offset: 2 }
309        })
310      }
311      .width(ConfigData.WH_100_100)
312      .height(ConfigData.WH_100_100)
313    }
314    .backgroundColor($r("sys.color.ohos_id_color_sub_background"))
315    .width(ConfigData.WH_100_100)
316    .height(ConfigData.WH_100_100)
317  }
318
319  // --------------------------- updateView -----------------------
320  /**
321   * Update view data
322   */
323  clearViewData() {
324    AppStorage.SetOrCreate("checkMessage", '');
325    this.password = '';
326    this.passwordCircle = ["", "", "", "", "", ""];
327    this.mController.bindComponent(this).initData();
328    this.updateView();
329  }
330
331  /**
332   * Update view
333   */
334  updateView() {
335    this.pageTitle = this.getPageTitle();
336    this.inputMessage = this.getInputMessage();
337    this.unlockMethodList = this.getUnlockMethodList();
338    this.buttonVisibility = this.getButtonVisibility();
339  }
340
341  /**
342   * Get page title
343   *
344   * @return : page title
345   */
346  getPageTitle(): Resource {
347    let title: Resource = $r('app.string.password_enter_password');
348    switch (this.passwordType) {
349      case PinSubType.PIN_SIX:
350
351      case PinSubType.PIN_NUMBER:
352        title = $r('app.string.password_title_number');
353        break;
354
355      case PinSubType.PIN_MIXED:
356        title = $r('app.string.password_title_character');
357        break;
358    }
359    return title;
360  }
361
362  /**
363   * Get input message
364   *
365   * @return : message
366   */
367  getInputMessage(): Resource {
368    let inputMessage: Resource = $r("app.string.endTextEmpty");
369    if (this.isInputFirstTime) {
370      switch (this.passwordType) {
371        case PinSubType.PIN_SIX:
372          inputMessage = $r('app.string.password_message_number_6');
373          break;
374
375        case PinSubType.PIN_NUMBER:
376          inputMessage = $r('app.string.password_message_custom');
377          break;
378
379        case PinSubType.PIN_MIXED:
380          inputMessage = $r('app.string.password_message_character');
381          break;
382      }
383    } else {
384      inputMessage = $r('app.string.password_message_repeat');
385    }
386    return inputMessage;
387  }
388
389  /**
390   * Get unlock method list.
391   *
392   * @return : unlock method list
393   */
394  getUnlockMethodList(): RadioListItem[] {
395    let list: RadioListItem[] = [];
396    if (!this.isInputFirstTime) {
397      return list;
398    }
399
400    if (this.passwordType != PinSubType.PIN_SIX) {
401      list.push({
402        settingType: PinSubType.PIN_SIX,
403        settingTitle: $r('app.string.password_item_text_number_6')
404      })
405    }
406
407    if (this.passwordType != PinSubType.PIN_NUMBER) {
408      list.push({
409        settingType: PinSubType.PIN_NUMBER,
410        settingTitle: $r('app.string.password_item_text_custom')
411      })
412    }
413
414    if (this.passwordType != PinSubType.PIN_MIXED) {
415      list.push({
416        settingType: PinSubType.PIN_MIXED,
417        settingTitle: $r('app.string.password_item_text_character')
418      })
419    }
420    return list;
421  }
422
423  /**
424   * Get button visibility
425   *
426   * @return : button visibility
427   */
428  getButtonVisibility(): Visibility {
429    return this.passwordType == PinSubType.PIN_SIX ? Visibility.Hidden : Visibility.Visible;
430  }
431}
432
433// The check message need to change real time, put it in child component, so parent component does not refresh.
434@Component
435struct CheckText {
436  @StorageLink("checkMessage")
437  private checkMessage: string | Resource = '';
438
439  build() {
440    Text(this.checkMessage ? this.checkMessage : $r('app.string.password_set_prompt'))
441      .fontSize($r('sys.float.ohos_id_text_size_body2'))
442      .fontWeight(FontWeight.Medium)
443      .fontColor($r('sys.color.ohos_id_color_warning'))
444      .align(Alignment.Center)
445      .textAlign(TextAlign.Center)
446      .margin({ top: $r('app.float.distance_4'), bottom: $r('app.float.distance_24') })
447  }
448}
449
450/**
451 * Choose Unlock Method Dialog
452 */
453@CustomDialog
454struct chooseUnlockMethodDialog {
455  controller?: CustomDialogController;
456  private dataList: RadioListItem[] = [];
457  private checkedValue: string = '';
458  private dialogTitle: string | Resource = "";
459  private chosenAction: (value: number) => void = () => {};
460  @State isTouched: Boolean = false;
461
462  closeDialog() {
463    this.controller?.close();
464  }
465
466  build() {
467    Column() {
468      Text(this.dialogTitle)
469        .height($r('app.float.wh_value_56'))
470        .margin({ left: $r('app.float.wh_value_24') })
471        .width(ConfigData.WH_100_100)
472        .fontSize($r('app.float.font_20'))
473        .fontColor($r("sys.color.ohos_id_color_primary"))
474        .fontWeight(500)
475
476      RadioListComponent({
477        dataList: this.dataList,
478        checkedValue: this.checkedValue,
479        showRadio: false,
480        onChange: (item: RadioListItem) => {
481          if (this.chosenAction != null) {
482            LogUtil.info(ConfigData.TAG + 'chooseUnlockMethodDialog : onCheckedAction : call back');
483            this.chosenAction(item.settingType? item.settingType : 0);
484          }
485          this.closeDialog();
486        }
487      })
488
489      Text($r('app.string.cancel'))
490        .fontSize($r('app.float.application_button_subtitle_size'))
491        .fontColor($r('sys.color.ohos_id_color_focused_bg'))
492        .textAlign(TextAlign.Center)
493        .fontWeight(500)
494        .width(ConfigData.WH_100_100)
495        .height($r("app.float.wh_value_56"))
496        .margin({ top: $r("app.float.wh_value_6") })
497        .padding({ top: $r("app.float.wh_value_12"), bottom: $r("app.float.wh_value_6") })
498        .borderRadius($r('app.float.radius_20'))
499        .linearGradient(this.isTouched ? {
500                                           angle: 90,
501                                           direction: GradientDirection.Right,
502                                           colors: [[$r("app.color.DCEAF9"), 0.0], [$r("app.color.FAFAFA"), 1.0]]
503                                         } : {
504                                               angle: 90,
505                                               direction: GradientDirection.Right,
506                                               colors: [[$r("sys.color.ohos_id_color_foreground_contrary"), 1], [$r("sys.color.ohos_id_color_foreground_contrary"), 1]]
507                                             })
508        .onTouch((event?: TouchEvent) => {
509          if (event?.type === TouchType.Down) {
510            this.isTouched = true;
511          }
512
513          if (event?.type === TouchType.Up) {
514            this.isTouched = false;
515          }
516        })
517        .onClick(() => {
518          this.closeDialog();
519        })
520        .alignSelf(ItemAlign.Center)
521    }
522  }
523}