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