• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2021-2023 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 window from '@ohos.window';
17import common from '@ohos.app.ability.common';
18import Constants from '../common/utils/constant';
19import { CustomContentDialog } from '@ohos.arkui.advanced.Dialog';
20import { Log, getFontSizeScale, } from '../common/utils/utils';
21import { EventObserver } from '../common/observer/EventObserver';
22import { PermissionGroup, ButtonStatus } from '../common/model/definition';
23import { CallerAppInfo, PermissionGroupConfig } from '../common/model/typedef';
24import { LocationCanvas } from '../common/components/location';
25import { buttonResource } from '../common/model/permissionGroup';
26import { GrantDialogIntent } from '../ServiceExtAbility/GrantDialogIntent';
27import { GrantDialogViewModel } from '../ServiceExtAbility/GrantDialogViewModel';
28import { GrantDialogViewState } from '../ServiceExtAbility/GrantDialogViewState';
29
30@Extend(Button)function customizeButton() {
31  .buttonStyle(ButtonStyleMode.TEXTUAL)
32  .fontColor($r('sys.color.font_emphasize'))
33  .width(Constants.HALF_LENGTH)
34}
35
36@Extend(Text)function titleText() {
37  .fontWeight(FontWeight.Bold)
38  .fontColor($r('sys.color.font_primary'))
39  .textAlign(TextAlign.Center)
40  .textOverflow({ overflow: TextOverflow.Ellipsis })
41  .maxLines(Constants.SECURITY_HEADER_MAX_LINES)
42}
43
44const EVENT_BUNDLE_RESOURCES_CHANGED = 'usual.event.BUNDLE_RESOURCES_CHANGED';
45
46@Entry({ useSharedStorage: true })
47@Component
48struct dialogPlusPage {
49  private context = this.getUIContext().getHostContext() as common.ServiceExtensionContext;
50  private resourceChangeObserver: EventObserver = new EventObserver([EVENT_BUNDLE_RESOURCES_CHANGED]);
51  @LocalStorageLink('callerAppInfo') callerAppInfo: CallerAppInfo = {} as CallerAppInfo;
52  @LocalStorageLink('win') win: window.Window = {} as window.Window;
53  @State viewModel: GrantDialogViewModel = new GrantDialogViewModel(this.callerAppInfo, this.win);
54  @State viewState: GrantDialogViewState = this.viewModel.getViewState();
55  private refreshData = (): void => {
56    if (this.callerAppInfo === undefined) {
57      Log.error(`event error, callerAppInfo is undefined.`);
58      return;
59    }
60    try {
61      this.viewModel.processIntent(
62        new GrantDialogIntent.RefreshIntent(this.context, this.callerAppInfo)
63      );
64    } catch (error) {
65      Log.error(`try to refresh data faild, code: ${error.code}, message: ${error.message}.`);
66    }
67  }
68
69  dialogController: CustomDialogController | null = new CustomDialogController({
70    builder: CustomContentDialog({
71      contentBuilder: () => {
72        this.buildContent();
73      },
74      contentAreaPadding: { right: 0 }
75    }),
76    autoCancel: false
77  });
78
79  @Builder
80  DialogTitle() {
81    Row() {
82      Column() {
83        if (getFontSizeScale()) {
84          Text(this.viewState.grantGroups[this.viewState.curIndex].title)
85            .titleText()
86            .fontSize($r('sys.float.Title_S'))
87        } else {
88          Text(this.viewState.grantGroups[this.viewState.curIndex].title)
89            .titleText()
90            .minFontSize(Constants.TEXT_MIDDLE_FONT_SIZE)
91            .maxFontSize($r('sys.float.Title_S'))
92            .heightAdaptivePolicy(TextHeightAdaptivePolicy.MAX_LINES_FIRST)
93        }
94      }
95      .constraintSize({ minHeight: Constants.HEADLINE_HEIGHT })
96      .justifyContent(FlexAlign.Center)
97      .padding({
98        top: Constants.DEFAULT_PADDING_TOP,
99        bottom: Constants.DEFAULT_PADDING_BOTTOM,
100        left: Constants.PADDING_24,
101        right: Constants.PADDING_24
102      })
103    }
104  }
105
106  @Builder
107  buildContent(): void {
108    Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
109      Column() {
110          Image(this.viewState.grantGroups[this.viewState.curIndex].icon)
111            .width(Constants.DIALOG_ICON_WIDTH)
112            .height(Constants.DIALOG_ICON_HEIGHT)
113            .fillColor($r('sys.color.font_primary'))
114            .margin({ top: Constants.DIALOG_ICON_MARGIN_TOP })
115          if (this.viewState.grantGroups.length > 1) {
116            Text(`${this.viewState.curIndex + 1} / ${this.viewState.grantGroups.length}`)
117              .fontSize(Constants.DIALOG_LABEL_FONT_SIZE)
118              .fontColor($r('sys.color.font_secondary'))
119              .lineHeight(Constants.DIALOG_LABEL_LINE_HEIGHT)
120              .margin({ top: Constants.DIALOG_LABEL_MARGIN_TOP })
121          }
122          Scroll() {
123            Column() {
124              this.DialogTitle();
125
126              Row() {
127                Flex({ justifyContent: FlexAlign.Center }) {
128                  Text() {
129                      if (this.viewState.grantGroups[this.viewState.curIndex].readAndWrite) {
130                        Span(this.viewState.grantGroups[this.viewState.curIndex].readAndWrite)
131                        Span(this.viewState.grantGroups[this.viewState.curIndex].reason ? $r('app.string.comma') : $r('app.string.period'))
132                      }
133                      Span(this.showReason())
134                  }
135                  .textAlign(TextAlign.Start)
136                  .fontColor($r('sys.color.font_primary'))
137                  .fontSize($r('sys.float.Body_L'))
138                  .maxFontScale(Constants.DIALOG_TEXT_MAX_SCALE)
139                  .margin({
140                    left: Constants.MARGIN_24,
141                    right: Constants.MARGIN_24,
142                    bottom: Constants.MARGIN_8
143                  })
144                }
145              }
146
147              if (
148                this.viewState.locationFlag > Constants.LOCATION_NONE &&
149                this.viewState.grantGroups[this.viewState.curIndex].groupName === PermissionGroup.LOCATION
150              ) {
151                LocationCanvas({ viewState: $viewState })
152              }
153            }
154          }.constraintSize({ maxHeight: Constants.MAXIMUM_HEADER_HEIGHT })
155          if (
156            this.viewState.grantGroups[this.viewState.curIndex].buttonList.length <= 2 &&
157            this.calculateButtonWidth(this.viewState.grantGroups[this.viewState.curIndex].buttonList)
158          ) {
159            //横向布局
160            Row() {
161              Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) {
162                Button(buttonResource.get(this.viewState.grantGroups[this.viewState.curIndex].buttonList[0]))
163                  .customizeButton()
164                  .onClick(() => {
165                    this.processClick(this.viewState.grantGroups[this.viewState.curIndex].buttonList[0]);
166                  })
167                Divider()
168                  .color($r('sys.color.comp_divider'))
169                  .vertical(true)
170                  .strokeWidth(Constants.DIALOG_DIVIDER)
171                  .height(Constants.DIVIDER_HEIGHT)
172                  .opacity(0.2)
173                  .margin({ left: Constants.MARGIN_8, right: Constants.MARGIN_8 })
174                Button(buttonResource.get(this.viewState.grantGroups[this.viewState.curIndex].buttonList[1]))
175                  .customizeButton()
176                  .onClick(() => {
177                    this.processClick(this.viewState.grantGroups[this.viewState.curIndex].buttonList[1]);
178                  })
179              }.margin({
180                left: Constants.MARGIN_16,
181                right: Constants.MARGIN_16,
182                bottom: Constants.MARGIN_8
183              })
184            }
185          } else {
186            //纵向布局
187            Column() {
188              ForEach(
189                this.viewState.grantGroups[this.viewState.curIndex].buttonList, (buttonStatus: ButtonStatus, idx: number
190              ) => {
191                Button(buttonResource.get(buttonStatus))
192                  .customizeButton()
193                  .width(Constants.FULL_WIDTH)
194                  .margin({
195                    bottom: idx + 1 < this.viewState.grantGroups[this.viewState.curIndex].buttonList.length ?
196                      Constants.MARGIN_4 : 0
197                  })
198                  .onClick(() => {
199                    this.processClick(buttonStatus);
200                  })
201              })
202            }
203            .padding({ left: Constants.PADDING_16, right: Constants.PADDING_16 })
204          }
205      }
206      .padding({ bottom: Constants.PADDING_8 })
207      .clip(true)
208    }
209  }
210
211  build() {}
212
213  showReason(): ResourceStr {
214    if (this.viewState.grantGroups[this.viewState.curIndex].groupName === PermissionGroup.LOCATION) {
215      if (
216        (this.viewState.locationFlag === Constants.LOCATION_FUZZY) ||
217        (this.viewState.locationFlag === Constants.LOCATION_BOTH_FUZZY)
218      ) {
219        return $r('app.string.close_exact_position');
220      }
221    }
222    return this.viewState.grantGroups[this.viewState.curIndex].reason;
223  }
224
225  calculateButtonWidth(buttonStatus: ButtonStatus[]): boolean {
226    let denyText = buttonResource.get(buttonStatus[0]);
227    let allowText = buttonResource.get(buttonStatus[1]);
228    let maxButtonTextLength = Math.max(
229      this.getUIContext().getMeasureUtils().measureText({ textContent: denyText }),
230      this.getUIContext().getMeasureUtils().measureText({ textContent: allowText })
231    )
232
233    Log.info(`px2vp(maxButtonTextLength): ${this.getUIContext().px2vp(maxButtonTextLength)}`);
234    if (this.getUIContext().px2vp(maxButtonTextLength) > Constants.DIALOG_BUTTON_MAX_WIDTH) {
235      return false;
236    }
237
238    return true;
239  }
240
241  aboutToAppear() {
242    this.viewModel.processIntent(new GrantDialogIntent.InitIntent(this.context)).then(result => {
243      this.dialogController?.open();
244    })
245    this.context.eventHub.on('refresh', () => {
246      this.refreshData();
247    })
248    this.resourceChangeObserver.register(this.refreshData);
249  }
250
251  aboutToDisappear() {
252    this.dialogController = null;
253    this.context.eventHub.off('refresh');
254    this.resourceChangeObserver.unregister();
255  }
256
257  processClick(buttonStatus: ButtonStatus) {
258    let groupConfig: PermissionGroupConfig = this.viewState.grantGroups[this.viewState.curIndex];
259    if (this.callerAppInfo === undefined) {
260      Log.error(`processClick faild, callerAppInfo is undefined.`);
261      return;
262    }
263    let clickIntent: GrantDialogIntent.ClickIntent =
264      new GrantDialogIntent.ClickIntent(this.context, groupConfig, this.callerAppInfo, buttonStatus);
265    this.viewModel.processIntent(clickIntent);
266  }
267
268}