• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2025 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 { BreakpointConstants } from '../common/constants/BreakpointConstants';
17import CommonConstants from '../common/constants/CommonConstants';
18import CustomScanViewModel, { ScanResults } from '../viewmodel/CustomScanViewModel';
19import { MaskLayer } from './MaskLayer';
20import { ScanLine } from './ScanLine';
21import { CodeLayout } from './CommonCodeLayout';
22import { ScanSize, XComponentSize } from '../model/ScanSize';
23import { PromptTone } from '../model/PromptTone';
24import { common } from '@kit.AbilityKit';
25
26/**
27 * 扫码控制组件
28 */
29@Component
30export default struct CustomScanCtrlComp {
31  @StorageLink('currentBreakpoint') currentBreakpoint: string = BreakpointConstants.BREAKPOINT_SM;
32  @Consume('subPageStack') subPageStack: NavPathStack;
33  // 自定义扫码vm实例
34  @Consume('customScanVM') customScanVM: CustomScanViewModel;
35  @State scanSize: ScanSize = ScanSize.getInstance();
36  @State xComponentSize: XComponentSize = this.scanSize.xComponentSize;
37  // 相机闪光灯开启状态
38  @State isCameraLightOpen: boolean = false;
39  // 识别音效播放器
40  @State avPlayer: PromptTone = PromptTone.getInstance(getContext(this) as common.UIAbilityContext)
41
42  aboutToAppear() {
43    // 注册闪光灯状态回调
44    this.customScanVM.regCameraLightUpdateListener((isOpen: boolean) => {
45      this.isCameraLightOpen = isOpen;
46    })
47  }
48
49  build() {
50    Stack() {
51      Column() {
52        Row() {
53          // 自定义图库按钮
54          Image($r('app.media.custom_scan_picture'))
55            .width(CommonConstants.SCAN_CTRL_BTN_CLOSE_SIZE)
56            .height(CommonConstants.SCAN_CTRL_BTN_CLOSE_SIZE)
57            .fillColor(Color.White)
58            .backgroundColor(Color.Gray)
59            .alignSelf(ItemAlign.Start)
60            .margin({
61              top: $r('app.integer.custom_scan_btn_scan_close_margin_top'),
62              right: $r('app.integer.custom_scan_btn_scan_close_margin_left')
63            })
64            .padding($r('app.integer.custom_scan_btn_scan_close_padding'))
65            .clip(new Circle({
66              width: CommonConstants.SCAN_CTRL_BTN_CLOSE_SIZE,
67              height: CommonConstants.SCAN_CTRL_BTN_CLOSE_SIZE
68            }))
69            .onClick(async () => {
70              // 识别图库照片
71              const detectResult = await this.customScanVM.detectFromPhotoPicker();
72              if (!detectResult) {
73                return;
74              }
75
76              // 二维码识别结果展示
77              this.subPageStack.pushPathByName(CommonConstants.SUB_PAGE_DETECT_BARCODE, detectResult, true);
78            })
79        }
80        .width('100%')
81        .direction(Direction.Rtl)
82
83        Column() {
84          this.ScanLineBuilder()
85        }.layoutWeight(1)
86
87        // 扫描二维码文案
88        Text($r('app.string.custom_scan_text_put_code_to_scan'))
89          .height($r('app.string.custom_scan_text_scan_height'))
90          .fontSize($r('app.integer.custom_scan_text_scan_font_size'))
91          .fontColor(Color.White)
92          .margin({ top: $r('app.integer.custom_scan_text_scan_margin_top') })
93
94        // 闪光灯按钮,启动相机流后才能使用
95        Image($r('app.media.custom_scan_camera_light'))
96          .width(CommonConstants.SCAN_CTRL_BTN_LIGHT_SIZE)
97          .height(CommonConstants.SCAN_CTRL_BTN_LIGHT_SIZE)
98          .fillColor(this.isCameraLightOpen ? Color.Yellow : Color.White)
99          .onClick(() => {
100            this.customScanVM.updateFlashLightStatus();
101          })
102
103        Blank().height($r('app.string.custom_scan_10_percent'))
104      }
105
106      this.CodeLayoutBuilder();
107    }
108    .width('100%')
109    .height('100%')
110  }
111
112  /**
113   * 扫描动画
114   * @returns {void}
115   */
116  @Builder
117  ScanLineBuilder() {
118    if (this.customScanVM.isScanLine) {
119      Column() {
120        ScanLine()
121          .constraintSize({
122            minHeight: 100
123          })
124      }
125      .justifyContent(FlexAlign.Center)
126      .width('100%')
127    }
128  }
129
130  @Builder
131  CodeLayoutBuilder() {
132    // 扫描到二维码后展示二维码位置
133    if (this.customScanVM.isScanned) {
134      MaskLayer()
135      Column() {
136        CodeLayout({
137          xComponentSize: this.xComponentSize,
138          navHeight: this.scanSize.navHeight,
139          scanResults: this.customScanVM.scanResult,
140          avPlayer: this.avPlayer
141        })
142      }
143    }
144  }
145}
146