diff --git a/entry/src/main/ets/constants/CameraConstants.ets b/entry/src/main/ets/constants/CameraConstants.ets index b2b5d73e2e3499b1c30d0a9a27a7e5dd77b0b79b..41fd44c4110c4693c7202ea41e3a40cf13c34e6e 100644 --- a/entry/src/main/ets/constants/CameraConstants.ets +++ b/entry/src/main/ets/constants/CameraConstants.ets @@ -106,4 +106,8 @@ export class CameraConstants { * camera preview size */ public static readonly FRONT_HEIGHT: number = 3072; + /** + * count down time font size + */ + public static readonly COUNT_DOWN_FONT_SIZE: number = 100; } \ No newline at end of file diff --git a/entry/src/main/ets/pages/Index.ets b/entry/src/main/ets/pages/Index.ets index d796fd99e61b6365966bc8a0d378672315bd24a5..de72f864fb0546b2709f302cc89103bce9a1227c 100644 --- a/entry/src/main/ets/pages/Index.ets +++ b/entry/src/main/ets/pages/Index.ets @@ -56,6 +56,21 @@ let videoUri: string; let foldAbleStatus: number = 0; let currentFov: number = 1; +class CountDownTimerModifier implements ContentModifier { + applyContent(): WrappedBuilder<[TextTimerConfiguration]> { + return wrapBuilder(buildTextTimer); + } +} + +@Builder +function buildTextTimer(config: TextTimerConfiguration) { + Text(Math.ceil(config.count / 1000 - config.elapsedTime / 100).toString()) + .width(CameraConstants.FULL_SCREEN) + .fontSize(CameraConstants.COUNT_DOWN_FONT_SIZE) + .fontColor(Color.White) + .textAlign(TextAlign.Center) +} + @Component @Entry(storage) struct XComponentPage { @@ -76,13 +91,24 @@ struct XComponentPage { @StorageLink('photoUri') photoUri: string | Resource | PixelMap = ''; // Indicates whether the current preview type is an image @State currentPic: boolean = true; + // Flash icon @LocalStorageLink('flashPic') flashPic: Resource = $r('app.media.ic_camera_public_flash_off'); @LocalStorageLink('zoom') zoom: number = 1; @LocalStorageLink('isStabilization') isStabilization: boolean = false; @LocalStorageLink('isMovingPhoto') isMovingPhoto: boolean = false; + @LocalStorageLink('countDownTime') countDownTime: number = 0; + // Video record timer textTimerController: TextTimerController = new TextTimerController(); + // Custom count down timer + countDownTimeController: TextTimerController = new TextTimerController(); + countDownTimeModifier: CountDownTimerModifier = new CountDownTimerModifier(); + countDownInterval: number = 0; @State rotation: number = 0; + // Show zoom info on screen @State isShowZoom: boolean = false; + // Show count down time on screen + @State isCountingDown: boolean = false; + // Global context @State context: Context = this.getUIContext().getHostContext()!; onPageShow(): void { @@ -135,6 +161,7 @@ struct XComponentPage { } aboutToDisappear(): void { + clearInterval(this.countDownInterval); sensor.off(sensor.SensorId.GRAVITY); } @@ -253,13 +280,56 @@ struct XComponentPage { } ] ); + Image($r('sys.media.ohos_ic_public_clock')) + .fillColor(Color.White) + .height(CameraConstants.IMAGE_HEIGHT) + .margin(CameraConstants.MARGIN) + .visibility(this.isFront ? Visibility.Hidden : Visibility.Visible) + .rotate({ angle: this.rotation }) + .animation({ curve: curves.springMotion() }) + .bindMenu( + [ + { + value: 'off', + action: (): void => { + storage.setOrCreate('countDownTime', 0); + } + }, + { + value: '2s', + action: (): void => { + storage.setOrCreate('countDownTime', 2000); + } + }, + { + value: '5s', + action: (): void => { + storage.setOrCreate('countDownTime', 5000); + } + }, + { + value: '10s', + action: (): void => { + storage.setOrCreate('countDownTime', 10000); + } + }, + ] + ); } - .visibility(this.recording ? Visibility.Hidden : Visibility.Visible) + .visibility(this.recording || this.isCountingDown ? Visibility.Hidden : Visibility.Visible) .width(CameraConstants.FULL_SCREEN) .margin({ top: CameraConstants.MARGIN_TOP, bottom: CameraConstants.MARGIN_HEIGHT }) .justifyContent(FlexAlign.SpaceAround); Stack() { + TextTimer({ controller: this.countDownTimeController, isCountDown: true, count: this.countDownTime }) + .contentModifier(this.countDownTimeModifier) + .visibility(this.isCountingDown ? Visibility.Visible : Visibility.Hidden) + .position({ + top: this.isPhoto || this.foldAbleStatus === FoldStatus.FOLD_STATUS_EXPANDED ? 200 : 285 + }) + .zIndex(1) + XComponent({ type: XComponentType.SURFACE, controller: this.mXComponentController @@ -267,7 +337,7 @@ struct XComponentPage { .gesture( PinchGesture({ fingers: 2 }) .onActionUpdate((event: GestureEvent) => { - if (event && !this.isStabilization) { + if (event && !this.isStabilization && !this.isCountingDown) { this.zoom = currentFov * event.scale; this.isShowZoom = true; if (this.zoom > (this.isPhoto ? zoomRatioRange[1] : 15)) { @@ -342,13 +412,13 @@ struct XComponentPage { this.setZoom(); }) } - .visibility(this.isFront || this.isStabilization ? Visibility.Hidden : Visibility.Visible) + .visibility(this.isFront || this.isStabilization || this.isCountingDown ? Visibility.Hidden : Visibility.Visible) .margin({ top: this.isFoldAble ? CameraConstants.PREVIEW_HEIGHT_BUTTON : 450 }) Text(this.zoom === zoomRatioRange[0] ? 'wide angle' : this.zoom.toFixed(1) + 'x') .fontColor(Color.White) .margin({ top: 250 }) - .visibility(this.isShowZoom && !this.isFront ? Visibility.Visible : Visibility.Hidden) + .visibility(this.isShowZoom && !this.isFront && !this.isCountingDown ? Visibility.Visible : Visibility.Hidden) Column() { Row() { @@ -381,7 +451,7 @@ struct XComponentPage { } }) } - .visibility(this.recording ? Visibility.Hidden : Visibility.Visible) + .visibility(this.recording || this.isCountingDown ? Visibility.Hidden : Visibility.Visible) .justifyContent(FlexAlign.SpaceAround) .width(CameraConstants.CENTER_WIDTH) .height(CameraConstants.CAPTURE_SIZE) @@ -407,16 +477,32 @@ struct XComponentPage { .height(CameraConstants.CAPTURE_SIZE) .visibility(this.isPhoto ? Visibility.Visible : Visibility.Hidden) .onClick(() => { - capture(this.isFront); - this.currentPic = true; + if (this.countDownTime !== 0) { + this.isCountingDown = true; + this.countDownTimeController.start(); + } + this.countDownInterval = setTimeout(() => { + this.isCountingDown = false; + this.countDownTimeController.reset(); + capture(this.isFront); + this.currentPic = true; + }, this.countDownTime); }) Image($r('app.media.record')) .height(CameraConstants.CAPTURE_SIZE) .visibility(this.isPhoto ? Visibility.Hidden : this.recording ? Visibility.Hidden : Visibility.Visible) .onClick(async () => { - startRecord(); - this.textTimerController.start(); - this.recording = true; + if (this.countDownTime !== 0) { + this.isCountingDown = true; + this.countDownTimeController.start(); + } + this.countDownInterval = setTimeout(() => { + this.isCountingDown = false; + this.countDownTimeController.reset(); + startRecord(); + this.textTimerController.start(); + this.recording = true; + }, this.countDownTime); }) Image($r('app.media.recording')) .visibility(this.isPhoto ? Visibility.Hidden : this.recording ? Visibility.Visible : Visibility.Hidden) @@ -457,6 +543,7 @@ struct XComponentPage { this.isFront = cameraPosition !== 0; }) } + .visibility(this.isCountingDown ? Visibility.Hidden : Visibility.Visible) .width(CameraConstants.FULL_SCREEN) .justifyContent(FlexAlign.SpaceAround) @@ -520,5 +607,6 @@ export async function fromBack(context: Context): Promise { currentFov = 1; storage.setOrCreate('isStabilization', false); storage.setOrCreate('isMovingPhoto', false); + storage.setOrCreate('countDownTime', 0); cameraShooting(isVideo, cameraPosition, surfaceId, context, foldAbleStatus); } \ No newline at end of file