• 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 { uiObserver, UIObserver } from '@kit.ArkUI';
17import CustomScanViewModel, { ScanResults } from '../viewmodel/CustomScanViewModel';
18import CustomScanCameraComp from '../components/CustomScanCameraComp';
19import CustomScanCtrlComp from '../components/CustomScanCtrlComp';
20import CommonConstants from '../common/constants/CommonConstants';
21import { CommonTipsDialog } from '../components/CommonTipsDialog';
22import { DetectBarcodePage } from './DetectBarcodePage';
23
24/**
25 * 二维码扫描页面
26 * 实现步骤:
27 * 1.用户授权相机后初始化页面内子组件
28 * 2.进二维码扫描路由时监控折叠屏状态变化,实时重新初始化扫码服务和相机流尺寸
29 */
30@Component
31export struct CustomScanPage {
32  // 应用前后台标记
33  @StorageProp('isBackground') @Watch('onBackgroundUpdate') isBackground: boolean = false;
34  // 自页面栈
35  @Provide('subPageStack') subPageStack: NavPathStack = new NavPathStack();
36  // 自定义扫码vm实例
37  @Provide('customScanVM') customScanVM: CustomScanViewModel = CustomScanViewModel.getInstance();
38  // 授权标志
39  @State scanResult: ScanResults = this.customScanVM.scanResult
40  @State isGranted: boolean = false;
41  // 提示授权弹框
42  @State isDialogShow: boolean = false;
43
44  dialogController: CustomDialogController = new CustomDialogController({
45    builder: CommonTipsDialog({
46      isDialogShow: this.isDialogShow
47    }),
48    autoCancel: false,
49    customStyle: false,
50    alignment: DialogAlignment.Center
51  });
52  listener: (info: uiObserver.RouterPageInfo) => void = (info: uiObserver.RouterPageInfo) => {
53    let routerInfo: uiObserver.RouterPageInfo | undefined = this.queryRouterPageInfo();
54    if (info.pageId == routerInfo?.pageId) {
55      if (info.state == uiObserver.RouterPageState.ON_PAGE_SHOW) {
56        this.onComponentShow();
57      } else if (info.state == uiObserver.RouterPageState.ON_PAGE_HIDE) {
58        this.onComponentHide();
59      }
60    }
61  }
62
63  @Builder
64  pageMap(name: string) {
65    if (name === CommonConstants.SUB_PAGE_DETECT_BARCODE) {
66      NavDestination() {
67        DetectBarcodePage()
68      }
69      .hideTitleBar(true)
70    }
71  }
72
73  async aboutToAppear() {
74    // 注册routerPage更新监听
75    let uiObserver: UIObserver = this.getUIContext().getUIObserver();
76    uiObserver.on('routerPageUpdate', this.listener);
77
78    this.onComponentShow();
79  }
80
81  /**
82   * 组件出现时执行,包括前后台切换
83   */
84  async onComponentShow() {
85    // TODO:知识点:检测应用是否已被用户允许使用相机权限,未授权向申请授权
86    const isGranted = await this.customScanVM.reqCameraPermission();
87    if (!isGranted && !this.isDialogShow) {
88      // 用户未授权,给出提示
89      this.dialogController.open();
90      this.isDialogShow = true;
91    }
92    this.isGranted = isGranted;
93  }
94
95  aboutToDisappear() {
96    // 取消监听
97    let uiObserver: UIObserver = this.getUIContext().getUIObserver();
98    uiObserver.off('routerPageUpdate', this.listener);
99  }
100
101  /**
102   * 应用前后台切换回调,进后台时需要释放扫码资源,进前台时需要重启扫码功能
103   * @returns {void}
104   */
105  onBackgroundUpdate(): void {
106    if (this.subPageStack.size() > 0) {
107      return;
108    }
109
110    if (this.isBackground) {
111      this.customScanVM.stopCustomScan();
112    } else {
113      this.customScanVM.restartCustomScan();
114    }
115  }
116
117  /**
118   * 组件隐藏时执行
119   */
120  onComponentHide() {
121    this.isDialogShow = false;
122    this.dialogController.close();
123  }
124
125  initScan(): void {
126    this.customScanVM.initCustomScan();
127  }
128
129  build() {
130    Navigation(this.subPageStack) {
131      Stack() {
132        if (this.isGranted) {
133          CustomScanCameraComp()
134        }
135        CustomScanCtrlComp()
136      }
137      .alignContent(Alignment.Center)
138      .backgroundColor(Color.Black)
139      .expandSafeArea([SafeAreaType.SYSTEM],[SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
140    }
141    .navDestination(this.pageMap)
142    .mode(NavigationMode.Stack)
143    .hideTitleBar(true)
144  }
145}