• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2023 Hunan OpenValley Digital Industry Development 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 */
15import { Permissions } from '@ohos.abilityAccessCtrl'
16import abilityAccessCtrl from '@ohos.abilityAccessCtrl'
17import router from '@ohos.router'
18import Logger from '../../utils/Logger'
19import CameraModel from '../../model/CameraModel'
20import User from '../data/User'
21import { BusinessError } from '@ohos.base'
22
23const TAG: string = '[CameraPage]'
24const PERMISSIONS: Array<Permissions> = ['ohos.permission.READ_MEDIA', 'ohos.permission.WRITE_MEDIA', 'ohos.permission.MEDIA_LOCATION', 'ohos.permission.MICROPHONE', 'ohos.permission.CAMERA']
25
26@Entry
27@Component
28struct CameraPage {
29  // 底部特效模拟图片资源数组
30  private imageList: Array<Resource> = [$r('app.media.app_icon'), $r('app.media.app_icon'), $r('app.media.app_icon'), $r('app.media.app_icon'), $r('app.media.app_icon'), $r('app.media.app_icon')];
31  // 文字资源数组
32  private textList: Array<Resource> = [$r('app.string.Word'), $r('app.string.Subsection'), $r('app.string.Video'), $r('app.string.Photo'), $r('app.string.Everyday'), $r('app.string.Live_streaming')];
33  // 侧边图标资源数组
34  private sidebarList_1: Array<Resource> = [$r('app.media.app_icon'), $r('app.media.app_icon'), $r('app.media.app_icon'), $r('app.media.app_icon'), $r('app.media.app_icon'), $r('app.media.app_icon')];
35  private sidebarList_2: Array<Resource> = [$r('app.media.app_icon'), $r('app.media.app_icon'), $r('app.media.app_icon'), $r('app.media.app_icon'), $r('app.media.app_icon'), $r('app.media.app_icon')];
36  private xComponentController: XComponentController = new XComponentController();
37  private textTimerController: TextTimerController = new TextTimerController();
38  private cameraModel: CameraModel = new CameraModel(getContext(this))
39  private scrollerHorText: Scroller = new Scroller();
40  private scrollerHorImage: Scroller = new Scroller();
41  private currentUser: User | null = null; // 当前用户信息
42  @State recordingStatus: number = 0; // 0:未录制 1:正在录制 2:结束录制
43  @State surfaceId: string = '-1';
44  @State format: string = 'mm:ss';
45  @State uploadFile: string = '';
46
47  pageTransition() {
48    // 登录页面从底部滑入滑出
49    PageTransitionEnter({ type: RouteType.Push, duration: 200 })
50      .slide(SlideEffect.Bottom)
51    PageTransitionExit({ type: RouteType.Pop, duration: 200 })
52      .slide(SlideEffect.Bottom)
53  }
54
55  aboutToAppear() {
56    let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager()
57    try {
58      atManager.requestPermissionsFromUser(getContext(this), PERMISSIONS).then((data) => {
59        this.cameraModel.createCamera(this.surfaceId);
60        Logger.info(TAG, 'requestPermissionsFromUser success')
61      }).catch((err: BusinessError) => {
62        Logger.info(TAG, `requestPermissionsFromUser err: ${JSON.stringify(err)}`)
63      })
64    } catch (err) {
65      Logger.info(TAG, `requestPermissionsFromUser catch err->${JSON.stringify(err)}`);
66    }
67    if (AppStorage.get("currentUser")) {
68      this.currentUser = AppStorage.get("currentUser")!;
69    }
70  }
71
72  onPageHide() {
73    Logger.info(TAG, 'page onPageHide');
74    this.stopVideo();
75    this.cameraModel.releaseCamera();
76  }
77
78  onPageShow() {
79    Logger.info(TAG, 'page onPageHide');
80    this.cameraModel.createCamera(this.surfaceId);
81  }
82
83  startVideo() {
84    Logger.info(TAG, 'page startVideo');
85    this.recordingStatus = 1;
86    this.textTimerController.reset();
87    this.textTimerController.start();
88    this.cameraModel.startVideo();
89  }
90
91  async stopVideo() {
92    Logger.info(TAG, 'page stopVideo');
93    this.recordingStatus = 2;
94    this.textTimerController.pause();
95    this.uploadFile = await this.cameraModel.stopVideo();
96    Logger.info(TAG, `page stopVideo uploadFile = ${this.uploadFile}`);
97  }
98
99  build() {
100    Column() {
101      Stack() {
102        XComponent({
103          id: 'xComponentId',
104          type: 'surface',
105          controller: this.xComponentController
106        })
107          .onLoad(() => {
108            Logger.info(TAG, 'onLoad is called')
109            // 设置XComponent创建的曲面宽为640vp,高为480vp
110            this.xComponentController.setXComponentSurfaceSize({ surfaceWidth: 640, surfaceHeight: 480 })
111            this.surfaceId = this.xComponentController.getXComponentSurfaceId()
112            Logger.info(TAG, `onLoad surfaceId: ${this.surfaceId}`)
113            this.cameraModel.createCamera(this.surfaceId)
114          })
115          .height('100%')
116          .width('100%')
117
118        Column() {
119          Row() {
120            Row() {
121              Image($r('app.media.app_icon'))
122                .width(30)
123                .height(30)
124                .objectFit(ImageFit.Contain)
125            }
126            .width(50)
127            .height(50)
128            .justifyContent(FlexAlign.Center)
129            .onClick(e => {
130              router.back()
131            })
132            .visibility(this.recordingStatus !== 1 ? Visibility.Visible : Visibility.None) // 正在录制时不显示
133
134            Row({ space: 8 }) {
135              Image($r('app.media.app_icon'))
136                .width(28)
137                .height(28)
138                .objectFit(ImageFit.Fill)
139                .borderRadius(14)
140              Text($r('app.string.Select_music'))
141                .textAlign(TextAlign.Center)
142                .fontColor($r('app.color.COLOR_FFFFFF'))
143                .fontSize(16)
144                .fontFamily($r('app.string.Font_family_regular'))
145                .borderRadius(14)
146            }
147            .width(132)
148            .height(48)
149            .borderRadius(12)
150            .backgroundColor($r('app.color.COLOR_669F9B9B'))
151            .justifyContent(FlexAlign.Center)
152            .visibility(this.recordingStatus !== 1 ? Visibility.Visible : Visibility.None) // 正在录制时不显示
153
154            Row() {
155              Image($r('app.media.app_icon'))
156                .width(26)
157                .height(26)
158                .objectFit(ImageFit.Contain)
159                .visibility(this.recordingStatus !== 2 ? Visibility.Visible : Visibility.None) // 非录制结束情况下显示
160              Image($r('app.media.app_icon'))
161                .width(26)
162                .height(26)
163                .objectFit(ImageFit.Contain)
164                .visibility(this.recordingStatus === 2 ? Visibility.Visible : Visibility.None) // 录制结束情况时显示
165            }
166            .width(42)
167            .height(42)
168          }
169          .width('100%')
170          .height('8%')
171          .justifyContent(this.recordingStatus !== 1 ? FlexAlign.SpaceBetween : FlexAlign.End)
172
173          Column({ space: 18 }) {
174            if (this.recordingStatus === 0) {
175              ForEach(this.sidebarList_1, (sidebar: Resource, index: number) => {
176                Image($r('app.media.app_icon'))
177                  .width(28)
178                  .height(28)
179                  .objectFit(ImageFit.Contain)
180                if (index === 1) {
181                  Divider()
182                    .vertical(false)
183                    .height(1)
184                    .width(22)
185                    .color($r('app.color.COLOR_FFFFFF'))
186                    .margin({ right: 4 })
187                }
188              })
189            } else if (this.recordingStatus === 2) {
190              ForEach(this.sidebarList_2, (sidebar: Resource, index: number) => {
191                Image($r('app.media.app_icon'))
192                  .width(28)
193                  .height(28)
194                  .objectFit(ImageFit.Contain)
195                if (index === 0) {
196                  Divider()
197                    .vertical(false)
198                    .height(1)
199                    .width(22)
200                    .color($r('app.color.COLOR_FFFFFF'))
201                    .margin({ right: 4 })
202                }
203                if (index === 1) {
204                  Text($r('app.string.Wen'))
205                    .textAlign(TextAlign.Center)
206                    .fontColor($r('app.color.COLOR_FFFFFF'))
207                    .fontSize(22)
208                    .fontFamily($r('app.string.Font_family_medium'))
209                    .margin({ right: 4 })
210                }
211              })
212            }
213          }
214          .width('100%')
215          .height('50%')
216          .padding({ top: 4, right: 14 })
217          .alignItems(HorizontalAlign.End)
218          .visibility(this.recordingStatus === 1 ? Visibility.None : Visibility.Visible) // 正在录制时不显示
219
220          Blank()
221
222          Column() {
223            Column() {
224              Column() {
225                TextTimer({ isCountDown: false, count: 60000, controller: this.textTimerController })
226                  .height('100%')
227                  .fontSize(18)
228                  .format(this.format)
229                  .fontColor($r('app.color.COLOR_FFFFFF'))
230              }
231              .justifyContent(FlexAlign.Start)
232              .visibility(this.recordingStatus === 1 ? Visibility.Visible : Visibility.Hidden)
233              .width('100%')
234              .height('30%')
235
236              // 文字列表
237              Scroll(this.scrollerHorText) {
238                Row({ space: 42 }) {
239                  ForEach(this.textList, (text: Resource, index: number) => {
240                    Text(text)
241                      .height('100%')
242                      .textAlign(TextAlign.Center)
243                      .fontColor(index === 2 ? $r('app.color.COLOR_EEC934') : $r('app.color.COLOR_FFFFFF'))
244                      .fontSize(16)
245                      .fontFamily($r('app.string.Font_family_medium'))
246                  })
247                }
248                .height('100%')
249                .justifyContent(FlexAlign.Start)
250                .alignItems(VerticalAlign.Bottom)
251              }
252              .width('70%')
253              .height('100%')
254              .scrollable(ScrollDirection.Horizontal)
255              .scrollBar(BarState.Off)
256              .visibility(this.recordingStatus === 0 ? Visibility.Visible : Visibility.Hidden)
257            }
258            .width('100%')
259            .height('15%')
260            .justifyContent(FlexAlign.Center)
261
262            Row() {
263              if (this.recordingStatus === 0) {
264                Column({ space: 6 }) {
265                  Image($r('app.media.app_icon'))
266                    .width(56)
267                    .height(56)
268                    .objectFit(ImageFit.Contain)
269                    .borderRadius(12)
270                  Text($r('app.string.Special'))
271                    .textAlign(TextAlign.Center)
272                    .fontColor($r('app.color.COLOR_FFFFFF'))
273                    .fontSize(16)
274                    .fontFamily($r('app.string.Font_family_medium'))
275                }
276                .width(64)
277                .height(64)
278
279                this.StartRecordComponent()
280
281                Column({ space: 6 }) {
282                  Image($r('app.media.app_icon'))
283                    .width(56)
284                    .height(56)
285                    .objectFit(ImageFit.Fill)
286                    .borderRadius(12)
287                  Text($r('app.string.Album'))
288                    .textAlign(TextAlign.Center)
289                    .fontColor($r('app.color.COLOR_FFFFFF'))
290                    .fontSize(16)
291                    .fontFamily($r('app.string.Font_family_medium'))
292                }
293                .width(64)
294                .height(64)
295              } else if (this.recordingStatus === 1) {
296                this.RecordingComponent()
297              } else {
298                this.PointComponent()
299              }
300            }
301            .width('100%')
302            .height('85%')
303            .justifyContent(FlexAlign.SpaceEvenly)
304          }
305          .width('100%')
306          .height('25%')
307        }
308        .width('100%')
309        .height('100%')
310      }
311      .width('100%')
312      .height('91%')
313      .borderRadius(12)
314
315      Row({ space: 12 }) {
316        if (this.recordingStatus === 0) {
317          Scroll(this.scrollerHorImage) {
318            Row({ space: 14 }) {
319              ForEach(this.imageList, (img: Resource) => {
320                Image($r('app.media.app_icon'))
321                  .width(56)
322                  .height(56)
323                  .objectFit(ImageFit.Fill)
324                  .borderRadius(10)
325              })
326            }
327            .height('100%')
328            .justifyContent(FlexAlign.Start)
329            .alignItems(VerticalAlign.Bottom)
330            .margin({ bottom: 1 })
331          }
332          .width('70%')
333          .height('100%')
334          .scrollable(ScrollDirection.Horizontal)
335          .scrollBar(BarState.Off)
336        } else if (this.recordingStatus === 1) {
337
338        } else if (this.recordingStatus === 2) {
339          Row() {
340            Image($r('app.media.app_icon'))
341              .width(28)
342              .height(28)
343              .objectFit(ImageFit.Fill)
344          }
345          .layoutWeight(1)
346          .height('80%')
347          .justifyContent(FlexAlign.Center)
348          .backgroundColor($r('app.color.COLOR_393939'))
349          .borderRadius(12)
350
351          Row({ space: 8 }) {
352            if (this.currentUser) {
353              Image($r('app.media.app_icon'))
354                .width(28)
355                .height(28)
356                .objectFit(ImageFit.Fill)
357                .borderRadius(14)
358            }
359            Text($r('app.string.Send_everyday'))
360              .textAlign(TextAlign.Center)
361              .fontColor($r('app.color.COLOR_FFFFFF'))
362              .fontSize(18)
363              .fontFamily($r('app.string.Font_family_regular'))
364              .borderRadius(14)
365          }
366          .layoutWeight(2)
367          .height('80%')
368          .justifyContent(FlexAlign.Center)
369          .backgroundColor($r('app.color.COLOR_393939'))
370          .borderRadius(12)
371
372          Row() {
373            Text($r('app.string.Next'))
374              .textAlign(TextAlign.Center)
375              .fontColor($r('app.color.COLOR_FFFFFF'))
376              .fontSize(18)
377              .fontFamily($r('app.string.Font_family_regular'))
378              .borderRadius(14)
379          }
380          .id('next')
381          .layoutWeight(2)
382          .height('80%')
383          .justifyContent(FlexAlign.Center)
384          .backgroundColor($r('app.color.COLOR_FC2B55'))
385          .borderRadius(12)
386          .onClick(e => {
387            this.recordingStatus = 0;
388            router.pushUrl({
389              url: 'appsampled/pages/PublishPage',
390              params: {
391                uploadFile: this.uploadFile
392              }
393            })
394          })
395        }
396
397      }
398      .width('100%')
399      .height('9%')
400      .justifyContent(FlexAlign.Center)
401      .padding({ left: 12, right: 12 })
402    }
403    .width('100%')
404    .height('100%')
405    .backgroundColor($r('app.color.COLOR_000000'))
406  }
407
408  @Builder
409  StartRecordComponent() {
410    Column() {
411      Column()
412        .width(80)
413        .height(80)
414        .backgroundColor(Color.Red)
415        .borderRadius(40)
416    }
417    .id('startVideo')
418    .width(100)
419    .height(100)
420    .border({ width: 5, color: $r('app.color.COLOR_FFFFFF'), radius: 50 })
421    .alignItems(HorizontalAlign.Center)
422    .justifyContent(FlexAlign.Center)
423    .onClick(e => {
424      this.startVideo();
425    })
426  }
427
428  @Builder
429  RecordingComponent() {
430    Stack() {
431      Column()
432        .width(60)
433        .height(60)
434        .borderRadius(30)
435        .backgroundColor($r('app.color.COLOR_E6FFFFFF'))
436      Column()
437        .width(20)
438        .height(20)
439        .borderRadius(4)
440        .backgroundColor(Color.Red)
441    }
442    .id('stopVideo')
443    .width(120)
444    .height(120)
445    .borderRadius(60)
446    .backgroundColor($r('app.color.COLOR_80FFFFFF'))
447    .onClick(e => {
448      this.stopVideo();
449    })
450  }
451
452  @Builder
453  PointComponent() {
454    Row({ space: 8 }) {
455      Text()
456        .width(4)
457        .height(4)
458        .backgroundColor($r('app.color.COLOR_CCFFFFFF'))
459        .borderRadius(2)
460      Text()
461        .width(6)
462        .height(6)
463        .backgroundColor($r('app.color.COLOR_CCFFFFFF'))
464        .borderRadius(3)
465      Text()
466        .width(8)
467        .height(8)
468        .backgroundColor($r('app.color.COLOR_CCFFFFFF'))
469        .borderRadius(4)
470
471      Text()
472        .width(10)
473        .height(10)
474        .backgroundColor($r('app.color.COLOR_FFFFFF'))
475        .borderRadius(5)
476
477      Text()
478        .width(8)
479        .height(8)
480        .backgroundColor($r('app.color.COLOR_CCFFFFFF'))
481        .borderRadius(4)
482      Text()
483        .width(6)
484        .height(6)
485        .backgroundColor($r('app.color.COLOR_CCFFFFFF'))
486        .borderRadius(3)
487      Text()
488        .width(4)
489        .height(4)
490        .backgroundColor($r('app.color.COLOR_CCFFFFFF'))
491        .borderRadius(2)
492    }
493    .width(100)
494    .height(30)
495    .alignItems(VerticalAlign.Center)
496    .justifyContent(FlexAlign.Center)
497  }
498}