From 7e4f0eeb19f27cd2ca2b75828667abbe42488c4d Mon Sep 17 00:00:00 2001 From: Kirill Kirichenko Date: Thu, 10 Oct 2024 14:41:27 +0000 Subject: [PATCH 1/7] WIP: page transition animation Signed-off-by: Kirill Kirichenko --- arkoala/arkui-common/src/ArkPageTransition.ts | 22 ++- arkoala/arkui/src/ArkCommon.ts | 8 +- arkoala/arkui/src/ArkComponentRoot.ts | 2 + arkoala/arkui/src/ArkPageTransition.ts | 145 ++++++++++++++++-- arkoala/arkui/src/ArkStructCommon.ts | 7 + arkoala/arkui/src/ArkTransition.ts | 2 +- .../interfaces/ArkCommonMethodInterface.ts | 15 ++ arkoala/arkui/src/shared/basic.ts | 1 - arkoala/framework/native/src/arkoala_api.h | 1 + arkoala/framework/native/src/library.cc | 27 +++- arkoala/framework/src/NativeModule.ts | 3 + arkoala/framework/src/NativeModuleEmpty.ts | 5 +- arkoala/framework/src/PeerNode.ts | 9 +- 13 files changed, 218 insertions(+), 29 deletions(-) diff --git a/arkoala/arkui-common/src/ArkPageTransition.ts b/arkoala/arkui-common/src/ArkPageTransition.ts index e34d443aa..83d1aee4d 100644 --- a/arkoala/arkui-common/src/ArkPageTransition.ts +++ b/arkoala/arkui-common/src/ArkPageTransition.ts @@ -20,13 +20,27 @@ export interface ArkPageTransitionParams { delay: number } +export interface ArkTranslateParams { + x?: string | number + y?: string | number + z?: string | number +} + +export interface ArkScaleParams { + x?: number + y?: number + z?: number + centerX?: string | number + centerY?: string | number +} + export class ArkPageTransitionData { params: Partial _onEnter?: (type: RouteType, progress: number) => void _onExit?: (type: RouteType, progress: number) => void _slide?: SlideEffect - _translate?: { x?: string | number | undefined; y?: string | number | undefined; z?: string | number | undefined; } - _scale?: { x?: number | undefined; y?: number | undefined; z?: number | undefined; centerX?: string | number | undefined; centerY?: string | number | undefined; } + _translate?: ArkTranslateParams + _scale?: ArkScaleParams _opacity?: number constructor(params: Partial) { @@ -44,11 +58,11 @@ export class ArkPageTransitionData { this._slide = value return this } - translate(value: { x?: string | number | undefined; y?: string | number | undefined; z?: string | number | undefined; }): this { + translate(value: ArkTranslateParams): this { this._translate = value return this } - scale(value: { x?: number | undefined; y?: number | undefined; z?: number | undefined; centerX?: string | number | undefined; centerY?: string | number | undefined; }): this { + scale(value: ArkScaleParams): this { this._scale = value return this } diff --git a/arkoala/arkui/src/ArkCommon.ts b/arkoala/arkui/src/ArkCommon.ts index b59f8f4cc..bde869b91 100644 --- a/arkoala/arkui/src/ArkCommon.ts +++ b/arkoala/arkui/src/ArkCommon.ts @@ -20,7 +20,7 @@ import { SortedArray } from "./shared/utils" import { endImplicitAnimation, startImplicitAnimations } from "./ArkAnimation" import { makeEventTarget } from "./Events" import { ArkPageTransitionEnter, ArkPageTransitionExit } from "./ArkPageTransition" -import { ArkTranstitionEffect, TransitionEffect } from "./ArkTransition" +import { ArkTransitionEffect, TransitionEffect } from "./ArkTransition" import { GesturePriority, setGestureEvent } from "./ArkGesture" import { int32, KoalaCallsiteKey } from "@koalaui/common" import { __id } from "@koalaui/runtime" @@ -580,9 +580,9 @@ export class ArkCommon extends ComponentBase implements ArkCommonMethodInterface if (this.checkPriority("transition")) { let peerNode = this.getNativePeerNode(); if (Object.keys(effect).includes('successor_')) { - let transtionEffectValue = new ArkTranstitionEffect(effect as TransitionEffect) - let appear: Float32Array = transtionEffectValue.appearValue - let disappear: Float32Array = transtionEffectValue.disappearValue + let transitionEffectValue = new ArkTransitionEffect(effect as TransitionEffect) + let appear: Float32Array = transitionEffectValue.appearValue + let disappear: Float32Array = transitionEffectValue.disappearValue withFloat32Array(appear, Access.READ, (appearPtr: KFloat32ArrayPtr) => { withFloat32Array(disappear, Access.READ, (disappearPtr: KFloat32ArrayPtr) => { nativeModule()._CommonMethod_chainedTransition(peerNode.ptr, appearPtr, disappearPtr, appear.length, disappear.length) diff --git a/arkoala/arkui/src/ArkComponentRoot.ts b/arkoala/arkui/src/ArkComponentRoot.ts index 9971e22bc..94ea92389 100644 --- a/arkoala/arkui/src/ArkComponentRoot.ts +++ b/arkoala/arkui/src/ArkComponentRoot.ts @@ -48,6 +48,8 @@ export function ArkComponentRoot( const state = CurrentRouterTransitionState() if (state) { RunEffect(state.visibility, visibility => { + console.log("#### Page ", state.pageId, " visibility changed to ", RouterTransitionVisibility[visibility]) + if (visibility == RouterTransitionVisibility.Showing) component.onPageShow?.() else if (visibility == RouterTransitionVisibility.Hiding) component.onPageHide?.() }) diff --git a/arkoala/arkui/src/ArkPageTransition.ts b/arkoala/arkui/src/ArkPageTransition.ts index 3beda5cc3..d69f5d230 100644 --- a/arkoala/arkui/src/ArkPageTransition.ts +++ b/arkoala/arkui/src/ArkPageTransition.ts @@ -15,26 +15,141 @@ import { int32 } from "@koalaui/common" import { contextNode, remember, scheduleCallback } from "@koalaui/runtime" -import { PeerNode, PeerNodeType } from "@koalaui/arkoala" -import { ArkPageTransitionData, ArkPageTransitionEnterComponent, ArkPageTransitionExitComponent, ArkPageTransitionParams, CurrentRouter, CurrentRouterTransitionState, RouterTransitionVisibility } from "@koalaui/arkui-common" +import { nativeModule, NodePointer, PeerNode, PeerNodeType } from "@koalaui/arkoala" +import { ArkPageTransitionData, ArkPageTransitionEnterComponent, ArkPageTransitionExitComponent, ArkPageTransitionParams, ArkTranslateParams, CurrentRouter, CurrentRouterTransitionState, RouterTransitionVisibility } from "@koalaui/arkui-common" +import { endImplicitAnimation, startImplicitAnimations } from "./ArkAnimation" +import { ArkUIAPIDimensionUnit, parseDimension } from "./shared/basic" +import { Access, withFloat32Array } from "@koalaui/interop" + +const ZERO_TRANSLATE = new Float32Array([0, ArkUIAPIDimensionUnit.PX, 0, ArkUIAPIDimensionUnit.PX, 0, ArkUIAPIDimensionUnit.PX]) + +function translateTransition(ptr: NodePointer, value: ArkTranslateParams) : Float32Array { + const xd = parseDimension(value.x, ArkUIAPIDimensionUnit.PX) + let x = xd.value + if (xd.unit == ArkUIAPIDimensionUnit.PERCENTAGE) { + x *= nativeModule()._GetX(ptr) + } + + const yd = parseDimension(value.y, ArkUIAPIDimensionUnit.PX) + let y = yd.value + if (yd.unit == ArkUIAPIDimensionUnit.PERCENTAGE) { + y *= nativeModule()._GetY(ptr) + } + + const z = parseDimension(value.z, ArkUIAPIDimensionUnit.PX) + + return new Float32Array([x, ArkUIAPIDimensionUnit.PX, y, ArkUIAPIDimensionUnit.PX, z.value, z.unit]) +} + +// see rosen_render_context.cpp:SlideTransitionEffect in ace_engine +function slideTransition(ptr: NodePointer, value: SlideEffect) : Float32Array { + const width = nativeModule()._GetMeasureWidth(ptr) + const height = nativeModule()._GetMeasureHeight(ptr) + let x = 0 + let y = 0 + switch (value) { + case SlideEffect.Left: + x = -width + break + case SlideEffect.Right: + x = width + break + case SlideEffect.Top: + y = -height + break + case SlideEffect.Bottom: + y = height + break + case SlideEffect.START: + x = -width // TODO: support RTL applications with x = width + break + case SlideEffect.END: + x = width // TODO: support RTL applications with x = -width + break + } + + return new Float32Array([x, ArkUIAPIDimensionUnit.PX, y, ArkUIAPIDimensionUnit.PX, 0, ArkUIAPIDimensionUnit.PX]) +} /** * @memo */ function NotifyPageTransition(pageId: int32, style: ArkPageTransitionData, state: RouterTransitionVisibility) { const node = contextNode(PeerNodeType) - console.log("NotifyPageTransition: shall notify", node.peer.id, "page", pageId, "state is", RouterTransitionVisibility[state]) + // console.log("NotifyPageTransition: shall notify", node.peer.id, "page", pageId, "state is", RouterTransitionVisibility[state]) const router = CurrentRouter() scheduleCallback(() => { - // TODO: make it driven by actual animation. - const time = (style.params.duration ?? 300) + (style.params.delay ?? 0) - if (time > 0) { - setTimeout(() => { - router?.onPageTransitionEnd(pageId) - }, time) - } else { - router?.onPageTransitionEnd(pageId) + console.log("#### Page transition animation: pageID =", pageId, " duration =", style.params.duration, + " curve = ", style.params.curve === undefined || (typeof style.params.curve === "string") ? style.params.curve : Curve[style.params.curve], + " delay = ", style.params.delay, + " state = ", RouterTransitionVisibility[state], + " opacity = ", style._opacity, + " slide = ", style._slide !== undefined ? SlideEffect[style._slide] : "undefined", + " translate = ", style._translate) + + if (style._opacity !== undefined) { + if (state == RouterTransitionVisibility.Hiding) { + nativeModule()._CommonMethod_opacityTransition(node.getPeerPtr(), 1.0) + } else if (state == RouterTransitionVisibility.Showing) { + nativeModule()._CommonMethod_opacityTransition(node.getPeerPtr(), style._opacity) + } + } + + if (style._slide !== undefined || style._translate !== undefined) { + if (state == RouterTransitionVisibility.Hiding) { + console.log("#### From zero") + + withFloat32Array(ZERO_TRANSLATE, Access.READ, tr => + nativeModule()._CommonMethod_translateOptions(node.getPeerPtr(), tr, 3)) + } else if (state == RouterTransitionVisibility.Showing) { + const translate = style._slide !== undefined ? + slideTransition(node.getPeerPtr(), style._slide) : + translateTransition(node.getPeerPtr(), style._translate!) + + console.log("#### From ", translate) + + withFloat32Array(translate, Access.READ, tr => + nativeModule()._CommonMethod_translateOptions(node.getPeerPtr(), tr, 3)) + } + } + + // nativeModule()._SetClipRect(node.getPeerPtr(), 0, 0, 10000, 10000) + + startImplicitAnimations({ + duration: style.params.duration, + curve: style.params.curve, + delay: style.params.delay, + onFinish: () => scheduleCallback(() => router?.onPageTransitionEnd(pageId)) + }) + + if (style._opacity !== undefined) { + if (state == RouterTransitionVisibility.Hiding) { + nativeModule()._CommonMethod_opacityTransition(node.getPeerPtr(), style._opacity) + } else if (state == RouterTransitionVisibility.Showing) { + nativeModule()._CommonMethod_opacityTransition(node.getPeerPtr(), 1.0) + } + } + + if (style._slide !== undefined || style._translate !== undefined) { + if (state == RouterTransitionVisibility.Hiding) { + const translate = style._slide !== undefined ? + slideTransition(node.getPeerPtr(), style._slide) : + translateTransition(node.getPeerPtr(), style._translate!) + + console.log("#### To ", translate) + + withFloat32Array(translate, Access.READ, tr => + nativeModule()._CommonMethod_translateOptions(node.getPeerPtr(), tr, 3)) + } else if (state == RouterTransitionVisibility.Showing) { + console.log("#### To zero") + withFloat32Array(ZERO_TRANSLATE, Access.READ, tr => + nativeModule()._CommonMethod_translateOptions(node.getPeerPtr(), tr, 3)) + } } + + // nativeModule()._SetClipRect(node.getPeerPtr(), 0, 0, 10000, 10000) + + endImplicitAnimation() }) } @@ -43,12 +158,12 @@ function NotifyPageTransition(pageId: int32, style: ArkPageTransitionData, state */ export function ArkPageTransitionEnter( /** @memo */ - style: (attributes: ArkPageTransitionEnterComponent) => void, + style: ((attributes: ArkPageTransitionEnterComponent) => void) | undefined, contentUnused: (() => void) | undefined, params: Partial ) { const receiver = remember(() => new ArkPageTransitionEnterComponent(params)) - style(receiver) + style?.(receiver) const state = CurrentRouterTransitionState() if (state?.visibility === RouterTransitionVisibility.Showing) { NotifyPageTransition(state.pageId, receiver, RouterTransitionVisibility.Showing) @@ -60,12 +175,12 @@ export function ArkPageTransitionEnter( */ export function ArkPageTransitionExit( /** @memo */ - style: (attributes: ArkPageTransitionExitComponent) => void, + style: ((attributes: ArkPageTransitionExitComponent) => void) | undefined, contentUnused: (() => void) | undefined, params: Partial ) { const receiver = remember(() => new ArkPageTransitionExitComponent(params)) - style(receiver) + style?.(receiver) const state = CurrentRouterTransitionState() if (state?.visibility === RouterTransitionVisibility.Hiding) { NotifyPageTransition(state.pageId, receiver, RouterTransitionVisibility.Hiding) diff --git a/arkoala/arkui/src/ArkStructCommon.ts b/arkoala/arkui/src/ArkStructCommon.ts index af4a565c9..5f3248abb 100644 --- a/arkoala/arkui/src/ArkStructCommon.ts +++ b/arkoala/arkui/src/ArkStructCommon.ts @@ -17,6 +17,7 @@ import { remember } from "@koalaui/runtime" import { ArkCommon } from "./ArkCommon"; import { CustomComponentImpl } from "./CustomComponent"; import { ArkComponentRoot } from "./ArkComponentRoot"; +import { ArkPageTransitionEnter, ArkPageTransitionExit } from "./ArkPageTransition"; export abstract class ArkCommonStruct0> extends ArkCommon { /** @memo */ @@ -249,4 +250,10 @@ export abstract class ArkStructBase extends CustomComponentImpl { content?: () => void, initializers?: Partial ): void + + /** @memo */ + pageTransition?(): void { + ArkPageTransitionEnter(undefined, undefined, { duration: 100 }) + ArkPageTransitionExit(undefined, undefined, { duration: 100 }) + } } diff --git a/arkoala/arkui/src/ArkTransition.ts b/arkoala/arkui/src/ArkTransition.ts index b05842a10..919ca9e6f 100644 --- a/arkoala/arkui/src/ArkTransition.ts +++ b/arkoala/arkui/src/ArkTransition.ts @@ -104,7 +104,7 @@ Effect extends TransitionEffects[Type] = TransitionEffects[Type] } } -export class ArkTranstitionEffect { +export class ArkTransitionEffect { original: TransitionEffect appearTransform: Array = [] disappearTransform: Array = [] diff --git a/arkoala/arkui/src/interfaces/ArkCommonMethodInterface.ts b/arkoala/arkui/src/interfaces/ArkCommonMethodInterface.ts index cd4ab2d4c..8619288c4 100644 --- a/arkoala/arkui/src/interfaces/ArkCommonMethodInterface.ts +++ b/arkoala/arkui/src/interfaces/ArkCommonMethodInterface.ts @@ -1,3 +1,18 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + export interface ArkCommonMethodInterface { aboutToDisappear(): void; diff --git a/arkoala/arkui/src/shared/basic.ts b/arkoala/arkui/src/shared/basic.ts index 9afad0d7f..4f277b0cc 100644 --- a/arkoala/arkui/src/shared/basic.ts +++ b/arkoala/arkui/src/shared/basic.ts @@ -120,7 +120,6 @@ export function parseDimension(dimension: Length, unit: ArkUIAPIDimensionUnit = return new GeoLength(value, unit) } } - console.error("Invalid dimension") return new GeoLength(0, unit) } diff --git a/arkoala/framework/native/src/arkoala_api.h b/arkoala/framework/native/src/arkoala_api.h index a9f88b47f..550435df4 100644 --- a/arkoala/framework/native/src/arkoala_api.h +++ b/arkoala/framework/native/src/arkoala_api.h @@ -5125,6 +5125,7 @@ struct ArkUIExtendedNodeAPI { ArkUI_Int32 (*getMeasureWidth)(ArkUINodeHandle node); void (*setMeasureHeight)(ArkUINodeHandle node, ArkUI_Int32 value); ArkUI_Int32 (*getMeasureHeight)(ArkUINodeHandle node); + void (*setClipRect)(ArkUINodeHandle node, ArkUI_Float32 x, ArkUI_Float32 y, ArkUI_Float32 w, ArkUI_Float32 h); void (*setX)(ArkUINodeHandle node, ArkUI_Int32 value); void (*setY)(ArkUINodeHandle node, ArkUI_Int32 value); ArkUI_Int32 (*getX)(ArkUINodeHandle node); diff --git a/arkoala/framework/native/src/library.cc b/arkoala/framework/native/src/library.cc index 84bb61259..8f071678b 100644 --- a/arkoala/framework/native/src/library.cc +++ b/arkoala/framework/native/src/library.cc @@ -271,7 +271,7 @@ KNativePointer impl_CreateNode(KInt type, KInt id, KInt flags) { return nullptr; } auto result = GetFullImpl()->getBasicAPI()->createNode(static_cast(type), id, flags); - ARKOALA_LOG("create " PUBLIC_NUMBER_FORMAT " " PUBLIC_NUMBER_FORMAT ": " PUBLIC_POINTER_FORMAT "\n", type, id, result); + // ARKOALA_LOG("create " PUBLIC_NUMBER_FORMAT " " PUBLIC_NUMBER_FORMAT ": " PUBLIC_POINTER_FORMAT "\n", type, id, result); return result; } KOALA_INTEROP_3(CreateNode, KNativePointer, KInt, KInt, KInt) @@ -372,6 +372,12 @@ KInt impl_GetMeasureHeight(KNativePointer nodePtr) { } KOALA_INTEROP_1(GetMeasureHeight, KInt, KNativePointer) +void impl_SetClipRect(KNativePointer nodePtr, KFloat x, KFloat y, KFloat w, KFloat h) { + ArkUINodeHandle node = reinterpret_cast(nodePtr); + return GetExtendedImpl()->setClipRect(node, x, y, w, h); +} +KOALA_INTEROP_V5(SetClipRect, KNativePointer, KFloat, KFloat, KFloat, KFloat) + void impl_SetX(KNativePointer nodePtr, KInt value) { ArkUINodeHandle node = reinterpret_cast(nodePtr); GetExtendedImpl()->setX(node, value); @@ -384,6 +390,18 @@ void impl_SetY(KNativePointer nodePtr, KInt value) { } KOALA_INTEROP_V2(SetY, KNativePointer, KInt) +KInt impl_GetX(KNativePointer nodePtr) { + ArkUINodeHandle node = reinterpret_cast(nodePtr); + return GetExtendedImpl()->getX(node); +} +KOALA_INTEROP_1(GetX, KInt, KNativePointer) + +KInt impl_GetY(KNativePointer nodePtr) { + ArkUINodeHandle node = reinterpret_cast(nodePtr); + return GetExtendedImpl()->getY(node); +} +KOALA_INTEROP_1(GetY, KInt, KNativePointer) + void impl_SetAlignment(KNativePointer nodePtr, KInt value) { ArkUINodeHandle node = reinterpret_cast(nodePtr); GetExtendedImpl()->setAlignment(node, value); @@ -784,6 +802,13 @@ void impl_CommonMethod_transform(KNativePointer nodePtr, KFloat *values, KInt le } KOALA_INTEROP_V3(CommonMethod_transform, KNativePointer, KFloat*, KInt) +void impl_CommonMethod_opacityTransition(KNativePointer nodePtr, KFloat value) { + ArkUINodeHandle node = reinterpret_cast(nodePtr); + GetNodeModifiers()->getCommonModifier()->setOpacity(node, value); +} +KOALA_INTEROP_V2(CommonMethod_opacityTransition, KNativePointer, KFloat) + + void impl_CommonMethod_visibleAreaChangeRatios(KNativePointer nodePtr, KFloat *value, KInt length) { // TODO: this API seems to be not exposed! ArkUINodeHandle node = reinterpret_cast(nodePtr); diff --git a/arkoala/framework/src/NativeModule.ts b/arkoala/framework/src/NativeModule.ts index 2c4db0ebd..bf04e8785 100644 --- a/arkoala/framework/src/NativeModule.ts +++ b/arkoala/framework/src/NativeModule.ts @@ -66,8 +66,11 @@ export interface NodeOps { _GetMeasureWidth(root: NodePointer): KInt _SetMeasureHeight(root: NodePointer, value: KInt): void _GetMeasureHeight(root: NodePointer): KInt + _SetClipRect(root: NodePointer, x: KFloat, y: KFloat, w: KFloat, h: KFloat): void _SetX(root: NodePointer, value: KInt): void _SetY(root: NodePointer, value: KInt): void + _GetX(root: NodePointer): KInt + _GetY(root: NodePointer): KInt _SetAlignment(root: NodePointer, value: KInt): void _GetAlignment(root: NodePointer): KInt _GetFrameNodeById(id: KInt): pointer diff --git a/arkoala/framework/src/NativeModuleEmpty.ts b/arkoala/framework/src/NativeModuleEmpty.ts index 7c55ed41c..93f3ba889 100644 --- a/arkoala/framework/src/NativeModuleEmpty.ts +++ b/arkoala/framework/src/NativeModuleEmpty.ts @@ -29,10 +29,13 @@ export class NativeModuleEmpty extends NativeModuleEmptyIntegrated implements Na _TextAttribute_labelResource(ptr: NodePointer, id: KInt, kind: KInt, name: KStringPtr, bundleName: KStringPtr, moduleName: KStringPtr): void {} _SetX(root: NodePointer, value: KFloat): void {} _SetY(root: NodePointer, value: KFloat): void {} + _GetX(root: NodePointer): KInt { return 0 } + _GetY(root: NodePointer): KInt { return 0 } _SetMeasureWidth(root: NodePointer, value: KInt): void {} _GetMeasureWidth(root: NodePointer): KInt { return 0 } _SetMeasureHeight(root: NodePointer, value: KInt): void {} _GetMeasureHeight(root: NodePointer): KInt { return 0 } + _SetClipRect(root: NodePointer, x: KFloat, y: KFloat, w: KFloat, h: KFloat): void {} _CanvasAttribute_beginPath(ptr: NodePointer): void {} _CanvasAttribute_closePath(ptr: NodePointer): void {} _CanvasAttribute_fill(ptr: NodePointer, value: KStringPtr): void {} @@ -274,7 +277,7 @@ export class NativeModuleEmpty extends NativeModuleEmptyIntegrated implements Na } else { // event is a Int32Array, do not copy it directly to UInt8Array, it casts to u8 with wrapping new Int32Array(wasmHeap()).set(event, result as KInt >> 2) - // Alterantively we can use the fact that src and dst are in the same array + // Alternatively we can use the fact that src and dst are in the same array // (globalThis as any)._heaps.HEAPU8().copyWithin(result, event.byteOffset, event.byteOffset + event.byteLength) } return 1 diff --git a/arkoala/framework/src/PeerNode.ts b/arkoala/framework/src/PeerNode.ts index 27e33c021..261abeb89 100644 --- a/arkoala/framework/src/PeerNode.ts +++ b/arkoala/framework/src/PeerNode.ts @@ -50,8 +50,8 @@ export class PeerCanvas extends Wrapper { super(ptr) } // TODO: commonize with Skoala! - drawRect(left: float32, top: float32, right: float32, botton: float32, paint: PeerPaint) { - nativeModule()._DrawRect(this.ptr, left, top, right, botton, paint.ptr) + drawRect(left: float32, top: float32, right: float32, bottom: float32, paint: PeerPaint) { + nativeModule()._DrawRect(this.ptr, left, top, right, bottom, paint.ptr) } } @@ -260,6 +260,8 @@ export class PeerNode extends IncrementalNode implements CustomizableNode { constructor(type: int32, flags: int32, name: string) { super(PeerNodeType) this.peer = NativePeerNode.create(this, type, this.id, flags) + console.log("#### Create PeerNode of type =", type, " id =", this.id, " name =", name, " ptr =", this.peer.ptr.toString(16)) + this.flags = flags this._name = name PeerNode.peerNodeMap.set(this.id, this) @@ -275,12 +277,15 @@ export class PeerNode extends IncrementalNode implements CustomizableNode { break } } + + console.log("#### onChildInserted: parent = ", this.peer.toString(), " child = ", peer.peer.toString()) this.peer.insertChildAfter(peer.peer, sibling?.peer) } } this.onChildRemoved = (child: IncrementalNode) => { let peer = findPeerNode(child) if (peer) { + console.log("#### onChildRemoved: parent = ", this.peer.toString(), " child = ", peer.peer.toString()) this.peer.removeChild(peer.peer) } } -- Gitee From 73c15c3e21ba9279171dc82e36637a19a5db6465 Mon Sep 17 00:00:00 2001 From: Kirill Kirichenko Date: Wed, 30 Oct 2024 15:20:52 +0300 Subject: [PATCH 2/7] Add Amination_issues.md doc Signed-off-by: Kirill Kirichenko --- arkoala/arkui/docs/Animation_issues.md | 47 +++++ arkoala/arkui/docs/transition-in.drawio.svg | 204 +++++++++++++++++++ arkoala/arkui/docs/transition-out.drawio.svg | 162 +++++++++++++++ 3 files changed, 413 insertions(+) create mode 100644 arkoala/arkui/docs/Animation_issues.md create mode 100644 arkoala/arkui/docs/transition-in.drawio.svg create mode 100644 arkoala/arkui/docs/transition-out.drawio.svg diff --git a/arkoala/arkui/docs/Animation_issues.md b/arkoala/arkui/docs/Animation_issues.md new file mode 100644 index 000000000..a1f5c6077 --- /dev/null +++ b/arkoala/arkui/docs/Animation_issues.md @@ -0,0 +1,47 @@ +# Page transition animation issues +There are two types of issues that we face when doing page transition animation with ArkRouter. + +## Transition In +Transition-In happens when we're about to open new page with Router with `router.pushUrl()` + +Here is the sequence of events happening on opening a new page: +![Transition In](transition-in.drawio.svg) + +### Problem +Animation ends before the UI tree of the newly displayed page is build so root container does not have content and +real size so transition in animation is considered to ba absent and only callback is executed after the delay. This ends with +no visible animation on the screen and the UI of the new page is just instantly shown on the screen instead of being animated +with preset animation parameters. + +### Possible solution +Create size change listener on the root component and start transition-in animation only after the root component gets +size different from 0.Possible problem for this solution is that for some short period of time we might be able to see the +whole page to be displayed on the screen in it's real coordinates and shortly after we well see the proper animation for +transition-in. + +### Questions +How to properly prepare a page for transition-in animation ? How to make sure the page has proper size and not visible such +that the animation smoothly brings it to the screen ? + +### Transition Out +Transition-Out happens when we call `router.back()` on the page. + +Here is the sequence of events happening on closing a page: +![Transition Out](transition-out.drawio.svg) + +### Problem +Animation on transition-out page may finish before the animation on the transition-in page (the previous on the stack) that's +about to be shown. When animation ends the root page of the transition-out page is removed from the UI tree and on next UI +rebuild the Peer node gets destroyed and its size becomes zero. When a page size becomes zero animation stops and transition +abruptly jumps to the final configuration. This behavior looks ugly. This may happen even it durations of both transition-in and +transition-out animations are similar. + +### Possible solutions +1. Put animations in a controlled sequence if possible such that transition-in animation does not call onFinish until +transition-in animation is finished too. +2. Do not remove the transition-out page from the UI tree until all animations are complete. This may probably be fixed +by enhancing transition-in animation with Promise logic. + +### Question +How to properly wait until transition-in animation finishes in transition-out onFinish handler and only after that remove +the page from UI tree ? \ No newline at end of file diff --git a/arkoala/arkui/docs/transition-in.drawio.svg b/arkoala/arkui/docs/transition-in.drawio.svg new file mode 100644 index 000000000..935141dda --- /dev/null +++ b/arkoala/arkui/docs/transition-in.drawio.svg @@ -0,0 +1,204 @@ + + + + + + + + + +
+
+
+ router.pushUrl("somePage") in called. A new page is created and added to Arkoala UI tree with Showing state. +
+
+
+
+ + router.pushUrl("somePage") in called. A new page... + +
+
+ + + + + + +
+
+
+ ArkStructBase creates ArkComponentRoot with corresponding PeerNode that creates ace_engine FrameNode with type ComponentRoot. +
+ It's size is zero, i.e. width and height of such node equal to 0. +
+
+
+
+ + ArkStructBase creates ArkComponentRoot with corr... + +
+
+ + + + + + +
+
+
+ ArkComponentRoot calls pageTransition() on the component. According to the Showing state ArkPageTransitionEnter calls internal NotifyPageTransition method. +
+
+
+
+ + ArkComponentRoot calls pageTransition() on the c... + +
+
+ + + + + + + + + +
+
+
+ Call PipelineContext.CloseImplicitAnimation +
+
+
+
+ + Call PipelineContext.CloseImplicitAnimation + +
+
+ + + + + + +
+
+
+ Set animation start state such as opacity, location, scale, center point, rect. +
+
+
+
+ + Set animation start state such as opacity,... + +
+
+ + + + + + +
+
+
+ Call PipelineContext.OpenImplicitAnimation in ace_engine. +
+
+
+
+ + Call PipelineContext.OpenImplicitAnimation... + +
+
+ + + + + + +
+
+
+ Set animation end state such as opacity, location, scale, center point, rect. +
+
+
+
+ + Set animation end state such as opacity, lo... + +
+
+ + + + + + +
+
+
+ Animation starts and ends indepenently of the UI tree build process. When it ends we receive onFinish event. In onFinish we switch the page visibility state to Visible. +
+
+
+
+ + Animation starts and ends indepenently of the UI... + +
+
+ + + + +
+
+
+ NotifyPageTransition initiates Transition-in animation. +
+
+
+
+ + NotifyPageTransition initiates Transition-in... + +
+
+ + + + +
+
+
+ ContentRoot is fiiled with components, gets measured and receives its real size. +
+
+
+
+ + ContentRoot is fiiled with components, gets meas... + +
+
+
+ + + + + Text is not SVG - cannot display + + + +
\ No newline at end of file diff --git a/arkoala/arkui/docs/transition-out.drawio.svg b/arkoala/arkui/docs/transition-out.drawio.svg new file mode 100644 index 000000000..2bd5ca2a0 --- /dev/null +++ b/arkoala/arkui/docs/transition-out.drawio.svg @@ -0,0 +1,162 @@ + + + + + + + + + +
+
+
+ router.back() is called and the the current page is set to Hiding state +
+
+
+
+ + router.back() is called and the the current pa... + +
+
+ + + + + + +
+
+
+ Incremental engine calls pageTransition() method which initiates AkkPageTransitionExit and then NotifyPageTransition with transition-out parameters. +
+
+
+
+ + Incremental engine calls pageTransition() meth... + +
+
+ + + + + + + +
+
+
+ NotifyPageTransition initiates Transition-Out animation. +
+
+
+
+ + NotifyPageTransition initiates Transition-O... + +
+
+ + + + + + +
+
+
+ Set animation start state such as opacity, location, scale, center point, rect. +
+
+
+
+ + Set animation start state such as opacity,... + +
+
+ + + + + + +
+
+
+ Call PipelineContext.OpenImplicitAnimation in ace_engine. +
+
+
+
+ + Call PipelineContext.OpenImplicitAnimation... + +
+
+ + + + + + +
+
+
+ Set animation end state such as opacity, location, scale, center point, rect. +
+
+
+
+ + Set animation end state such as opacity, lo... + +
+
+ + + + +
+
+
+ Call PipelineContext.CloseImplicitAnimation +
+
+
+
+ + Call PipelineContext.CloseImplicitAnimation + +
+
+ + + + +
+
+
+ Animation starts and ends. When it ends we receive onFinish event. In onFinish the topmost page is removed from the Arkoala UI tree. +
+
+
+
+ + Animation starts and ends. When it ends we rec... + +
+
+
+ + + + + Text is not SVG - cannot display + + + +
\ No newline at end of file -- Gitee From c923553273136ad8853223362c7c95e315997ac1 Mon Sep 17 00:00:00 2001 From: Kirill Kirichenko Date: Thu, 7 Nov 2024 13:59:58 +0300 Subject: [PATCH 3/7] Correct Transition-In with logging --- arkoala/arkui-common/src/Router.ts | 97 +++++++++++++++++++++----- arkoala/arkui/src/ArkAnimation.ts | 1 + arkoala/arkui/src/ArkPageTransition.ts | 8 +-- 3 files changed, 83 insertions(+), 23 deletions(-) diff --git a/arkoala/arkui-common/src/Router.ts b/arkoala/arkui-common/src/Router.ts index a3352297a..5c7edf935 100644 --- a/arkoala/arkui-common/src/Router.ts +++ b/arkoala/arkui-common/src/Router.ts @@ -23,6 +23,7 @@ import { mutableState, remember, RepeatByArray, + scheduleCallback, } from "@koalaui/runtime" import { observableProxyArray } from "./observable" @@ -62,6 +63,7 @@ class VisiblePage { setTransitionState(visibility: RouterTransitionVisibility, route?: RouteType) { this.transitionState.value = { pageId: this.version, visibility, route } + console.log(" ^^^^^^^^^^^^ Set visibility state of page = ", this.version, " to ", RouterTransitionVisibility[visibility]) } get transition(): RouterTransitionState { @@ -120,6 +122,8 @@ export class PageInfo { constructor(public depth: number, public page: string) { } } +export type PageTransition = () => void + /** * Interface providing page routing functionality. */ @@ -196,7 +200,8 @@ export interface Router { */ pageInfo: PageInfo - onPageTransitionEnd(pageId: int32): void + onPageTransitionEnd(pageId: int32, targetVisibility: RouterTransitionVisibility): void + schedulePageTransition(pageId: int32, transition: PageTransition): void } const CURRENT_ROUTER = "ohos.arkoala.router" @@ -309,28 +314,82 @@ class RouterImpl implements Router { return -1 } - onPageTransitionEnd(pageId: int32): void { + private pageTransitionMap = new Map>() + + private toString(transitions: PageTransition[]): string { + let result = "[ " + transitions.forEach((v, i) => result += (i + ": , ")) + return result + " ]" + } + + private transitionMapString(): string { + let result = "{ " + this.pageTransitionMap.forEach((value, key) => { + result += key + ":" + this.toString(value) + ", " + }) + return result + " }" + } + + schedulePageTransition(pageId: int32, transition: PageTransition): void { + let queuedTransitions = this.pageTransitionMap.get(pageId) + if (queuedTransitions === undefined) { + queuedTransitions = [] + this.pageTransitionMap.set(pageId, queuedTransitions) + } + + const length = queuedTransitions.length + queuedTransitions.splice(length, 0, transition) + console.log("$$$$$$ ->>>> schedule: pageID=", pageId, " transMap = ", this.transitionMapString()) + + if (length == 0) { + scheduleCallback(transition) + } + } + + onPageTransitionEnd(pageId: int32, targetVisibility: RouterTransitionVisibility): void { + console.log("onPageTransitionEnd ", pageId) + const index = this.findIndexByVersion(pageId) - if (index < 0) return - const page = this.state.visiblePages[index] - if (page.transition.visibility == RouterTransitionVisibility.Showing) { - if (pageId == this.state.currentActivePage.value) { - console.log("PAGE VISIBLE:", page.transition.pageId) - page.setTransitionState(RouterTransitionVisibility.Visible) - } else { - console.log("ERROR: showing page cannot be shown:", page.transition.route ? RouteType[page.transition.route] : "unknown") - page.setTransitionState(RouterTransitionVisibility.Hidden) + if (index >= 0) { + const page = this.state.visiblePages[index] + if (page.transition.visibility == targetVisibility) { + if (page.transition.visibility == RouterTransitionVisibility.Showing) { + if (pageId == this.state.currentActivePage.value) { + page.setTransitionState(RouterTransitionVisibility.Visible) + } else { + console.log("ERROR: showing page cannot be shown:", page.transition.route ? RouteType[page.transition.route] : "unknown") + page.setTransitionState(RouterTransitionVisibility.Hidden) + } + } else if (page.transition.visibility == RouterTransitionVisibility.Hiding) { + if (index < this.stack.length) { + console.log("PAGE HIDDEN:", page.transition.pageId) + page.setTransitionState(RouterTransitionVisibility.Hidden) + } else { + this.state.visiblePages.splice(index, 1) + console.log("PAGE REMOVED:", page.transition.pageId) + } + } else { + console.log("ERROR: no page transition:", pageId, RouterTransitionVisibility[page.transition.visibility], page.transition.route ? RouteType[page.transition.route] : "unknown") + } + } // Otherwise ignore transition because it has been updated during this animation period + } + + let queuedTransitions = this.pageTransitionMap.get(pageId) + if (queuedTransitions && queuedTransitions.length > 0) { + queuedTransitions.splice(0, 1) // Remove current transition + if (queuedTransitions.length == 0) { + this.pageTransitionMap.delete(pageId) } - } else if (page.transition.visibility == RouterTransitionVisibility.Hiding) { - if (index < this.stack.length) { - console.log("PAGE HIDDEN:", page.transition.pageId) - page.setTransitionState(RouterTransitionVisibility.Hidden) - } else { - console.log("PAGE REMOVED:", page.transition.pageId) - this.state.visiblePages.splice(index, 1) + + console.log("$$$$$$ ->>>> Remove current transition for pageID = ", pageId) + if (queuedTransitions.length > 0) { + console.log("$$$$$$ ->>>> Scheduling next transition for pageID = ", pageId) + scheduleCallback(queuedTransitions[0]) } + + console.log("$$$$$$ ->>>> Transition map = " + this.transitionMapString()) } else { - console.log("ERROR: no page transition:", RouterTransitionVisibility[page.transition.visibility], page.transition.route ? RouteType[page.transition.route] : "unknown") + console.log("$$$$$$ ->>>> PageTransitionMap for pageID=", pageId, " is empty or undefined") } } diff --git a/arkoala/arkui/src/ArkAnimation.ts b/arkoala/arkui/src/ArkAnimation.ts index 13a17a357..5db389cd3 100644 --- a/arkoala/arkui/src/ArkAnimation.ts +++ b/arkoala/arkui/src/ArkAnimation.ts @@ -30,6 +30,7 @@ export function startImplicitAnimations(param: AnimateParam) { param.onFinish!() return 0 }) + console.log("#### ->>>> Animation callback registered: ", methodId) } nativeModule()._OpenImplicitAnimation(animate.curve, value, methodId) } diff --git a/arkoala/arkui/src/ArkPageTransition.ts b/arkoala/arkui/src/ArkPageTransition.ts index d69f5d230..226211695 100644 --- a/arkoala/arkui/src/ArkPageTransition.ts +++ b/arkoala/arkui/src/ArkPageTransition.ts @@ -78,7 +78,7 @@ function NotifyPageTransition(pageId: int32, style: ArkPageTransitionData, state const node = contextNode(PeerNodeType) // console.log("NotifyPageTransition: shall notify", node.peer.id, "page", pageId, "state is", RouterTransitionVisibility[state]) const router = CurrentRouter() - scheduleCallback(() => { + router?.schedulePageTransition(pageId, () => { console.log("#### Page transition animation: pageID =", pageId, " duration =", style.params.duration, " curve = ", style.params.curve === undefined || (typeof style.params.curve === "string") ? style.params.curve : Curve[style.params.curve], " delay = ", style.params.delay, @@ -113,13 +113,13 @@ function NotifyPageTransition(pageId: int32, style: ArkPageTransitionData, state } } - // nativeModule()._SetClipRect(node.getPeerPtr(), 0, 0, 10000, 10000) + nativeModule()._SetClipRect(node.getPeerPtr(), 0, 0, 10000, 10000) startImplicitAnimations({ duration: style.params.duration, curve: style.params.curve, delay: style.params.delay, - onFinish: () => scheduleCallback(() => router?.onPageTransitionEnd(pageId)) + onFinish: () => router?.onPageTransitionEnd(pageId, state) }) if (style._opacity !== undefined) { @@ -147,7 +147,7 @@ function NotifyPageTransition(pageId: int32, style: ArkPageTransitionData, state } } - // nativeModule()._SetClipRect(node.getPeerPtr(), 0, 0, 10000, 10000) + nativeModule()._SetClipRect(node.getPeerPtr(), 0, 0, 10000, 10000) endImplicitAnimation() }) -- Gitee From 1078a742e60d646fe66e6e09676a372cbe1a8305 Mon Sep 17 00:00:00 2001 From: Kirill Kirichenko Date: Thu, 7 Nov 2024 14:57:15 +0300 Subject: [PATCH 4/7] Add scale transition Signed-off-by: Kirill Kirichenko --- arkoala/arkui/src/ArkPageTransition.ts | 87 +++++++++++++++++++------- 1 file changed, 66 insertions(+), 21 deletions(-) diff --git a/arkoala/arkui/src/ArkPageTransition.ts b/arkoala/arkui/src/ArkPageTransition.ts index 226211695..37128274f 100644 --- a/arkoala/arkui/src/ArkPageTransition.ts +++ b/arkoala/arkui/src/ArkPageTransition.ts @@ -16,10 +16,10 @@ import { int32 } from "@koalaui/common" import { contextNode, remember, scheduleCallback } from "@koalaui/runtime" import { nativeModule, NodePointer, PeerNode, PeerNodeType } from "@koalaui/arkoala" -import { ArkPageTransitionData, ArkPageTransitionEnterComponent, ArkPageTransitionExitComponent, ArkPageTransitionParams, ArkTranslateParams, CurrentRouter, CurrentRouterTransitionState, RouterTransitionVisibility } from "@koalaui/arkui-common" +import { ArkPageTransitionData, ArkPageTransitionEnterComponent, ArkPageTransitionExitComponent, ArkPageTransitionParams, ArkScaleParams, ArkTranslateParams, CurrentRouter, CurrentRouterTransitionState, RouterTransitionVisibility } from "@koalaui/arkui-common" import { endImplicitAnimation, startImplicitAnimations } from "./ArkAnimation" import { ArkUIAPIDimensionUnit, parseDimension } from "./shared/basic" -import { Access, withFloat32Array } from "@koalaui/interop" +import { Access, withFloat32Array, withInt32Array } from "@koalaui/interop" const ZERO_TRANSLATE = new Float32Array([0, ArkUIAPIDimensionUnit.PX, 0, ArkUIAPIDimensionUnit.PX, 0, ArkUIAPIDimensionUnit.PX]) @@ -41,6 +41,18 @@ function translateTransition(ptr: NodePointer, value: ArkTranslateParams) : Floa return new Float32Array([x, ArkUIAPIDimensionUnit.PX, y, ArkUIAPIDimensionUnit.PX, z.value, z.unit]) } +function translateScale(value: ArkScaleParams | undefined = undefined): {values:Float32Array, units: Int32Array } { + if (value) { + const centerX = parseDimension(value.centerX ?? 0, ArkUIAPIDimensionUnit.PX) + const centerY = parseDimension(value.centerY ?? 0, ArkUIAPIDimensionUnit.PX) + return {values: new Float32Array([value.x ?? 1.0, value.y ?? 1.0, 1.0, centerX.value, centerY.value]), + units: new Int32Array([centerX.unit, centerY.unit])} + } else { + return {values: new Float32Array([1.0, 1.0, 1.0, 0.0, 0.0]), + units: new Int32Array([ArkUIAPIDimensionUnit.PX, ArkUIAPIDimensionUnit.PX])} + } +} + // see rosen_render_context.cpp:SlideTransitionEffect in ace_engine function slideTransition(ptr: NodePointer, value: SlideEffect) : Float32Array { const width = nativeModule()._GetMeasureWidth(ptr) @@ -85,6 +97,7 @@ function NotifyPageTransition(pageId: int32, style: ArkPageTransitionData, state " state = ", RouterTransitionVisibility[state], " opacity = ", style._opacity, " slide = ", style._slide !== undefined ? SlideEffect[style._slide] : "undefined", + " scale = ", style._scale, " translate = ", style._translate) if (style._opacity !== undefined) { @@ -95,21 +108,37 @@ function NotifyPageTransition(pageId: int32, style: ArkPageTransitionData, state } } - if (style._slide !== undefined || style._translate !== undefined) { + if (style._slide !== undefined || style._translate !== undefined || style._scale !== undefined) { if (state == RouterTransitionVisibility.Hiding) { - console.log("#### From zero") + const scale = translateScale() + withFloat32Array(scale.values, Access.READ, scaleValues => { + withInt32Array(scale.units, Access.READ, scaleUnits => { + nativeModule()._CommonMethod_scaleOptions(node.getPeerPtr(), scaleValues, 5, scaleUnits, 2) + }) + }) withFloat32Array(ZERO_TRANSLATE, Access.READ, tr => nativeModule()._CommonMethod_translateOptions(node.getPeerPtr(), tr, 3)) - } else if (state == RouterTransitionVisibility.Showing) { - const translate = style._slide !== undefined ? - slideTransition(node.getPeerPtr(), style._slide) : - translateTransition(node.getPeerPtr(), style._translate!) - console.log("#### From ", translate) + } else if (state == RouterTransitionVisibility.Showing) { + if (style._scale !== undefined) { + const scale = translateScale(style._scale) + withFloat32Array(scale.values, Access.READ, scaleValues => { + withInt32Array(scale.units, Access.READ, scaleUnits => { + nativeModule()._CommonMethod_scaleOptions(node.getPeerPtr(), scaleValues, 5, scaleUnits, 2) + }) + }) + } - withFloat32Array(translate, Access.READ, tr => - nativeModule()._CommonMethod_translateOptions(node.getPeerPtr(), tr, 3)) + if (style._slide !== undefined) { + const translate = slideTransition(node.getPeerPtr(), style._slide) + withFloat32Array(translate, Access.READ, tr => + nativeModule()._CommonMethod_translateOptions(node.getPeerPtr(), tr, 3)) + } else if (style._translate !== undefined) { + const translate = translateTransition(node.getPeerPtr(), style._translate) + withFloat32Array(translate, Access.READ, tr => + nativeModule()._CommonMethod_translateOptions(node.getPeerPtr(), tr, 3)) + } } } @@ -130,18 +159,34 @@ function NotifyPageTransition(pageId: int32, style: ArkPageTransitionData, state } } - if (style._slide !== undefined || style._translate !== undefined) { + if (style._slide !== undefined || style._translate !== undefined || style._scale !== undefined) { if (state == RouterTransitionVisibility.Hiding) { - const translate = style._slide !== undefined ? - slideTransition(node.getPeerPtr(), style._slide) : - translateTransition(node.getPeerPtr(), style._translate!) - - console.log("#### To ", translate) - - withFloat32Array(translate, Access.READ, tr => - nativeModule()._CommonMethod_translateOptions(node.getPeerPtr(), tr, 3)) + if (style._scale !== undefined) { + const scale = translateScale(style._scale) + withFloat32Array(scale.values, Access.READ, scaleValues => { + withInt32Array(scale.units, Access.READ, scaleUnits => { + nativeModule()._CommonMethod_scaleOptions(node.getPeerPtr(), scaleValues, 5, scaleUnits, 2) + }) + }) + } + + if (style._slide !== undefined) { + const translate = slideTransition(node.getPeerPtr(), style._slide) + withFloat32Array(translate, Access.READ, tr => + nativeModule()._CommonMethod_translateOptions(node.getPeerPtr(), tr, 3)) + } if (style._translate !== undefined) { + const translate = translateTransition(node.getPeerPtr(), style._translate) + withFloat32Array(translate, Access.READ, tr => + nativeModule()._CommonMethod_translateOptions(node.getPeerPtr(), tr, 3)) + } } else if (state == RouterTransitionVisibility.Showing) { - console.log("#### To zero") + const scale = translateScale() + withFloat32Array(scale.values, Access.READ, scaleValues => { + withInt32Array(scale.units, Access.READ, scaleUnits => { + nativeModule()._CommonMethod_scaleOptions(node.getPeerPtr(), scaleValues, 5, scaleUnits, 2) + }) + }) + withFloat32Array(ZERO_TRANSLATE, Access.READ, tr => nativeModule()._CommonMethod_translateOptions(node.getPeerPtr(), tr, 3)) } -- Gitee From 7f33427d184c812c44d57c7afa2956e00d085b22 Mon Sep 17 00:00:00 2001 From: Kirill Kirichenko Date: Fri, 8 Nov 2024 16:52:12 +0300 Subject: [PATCH 5/7] Add progress animation Signed-off-by: Kirill Kirichenko --- arkoala/arkui-common/src/ArkPageTransition.ts | 6 ++- arkoala/arkui/src/ArkAnimation.ts | 2 +- arkoala/arkui/src/ArkPageTransition.ts | 54 +++++++++++++++++-- arkoala/arkui/src/shared/basic.ts | 5 +- arkoala/framework/native/src/arkoala_api.h | 5 +- arkoala/framework/native/src/library.cc | 16 ++++-- arkoala/framework/src/NativeModule.ts | 3 +- arkoala/framework/src/NativeModuleEmpty.ts | 4 +- interop/src/cpp/ets/convertors-ets.h | 20 +++++++ interop/src/cpp/jni/convertors-jni.h | 20 +++++++ interop/src/cpp/napi/convertors-napi.cc | 4 +- interop/src/cpp/napi/convertors-napi.h | 13 +++++ 12 files changed, 133 insertions(+), 19 deletions(-) diff --git a/arkoala/arkui-common/src/ArkPageTransition.ts b/arkoala/arkui-common/src/ArkPageTransition.ts index 83d1aee4d..4e7897d2b 100644 --- a/arkoala/arkui-common/src/ArkPageTransition.ts +++ b/arkoala/arkui-common/src/ArkPageTransition.ts @@ -34,10 +34,12 @@ export interface ArkScaleParams { centerY?: string | number } +export type ProgressCallback = (type: RouteType, progress: number) => void + export class ArkPageTransitionData { params: Partial - _onEnter?: (type: RouteType, progress: number) => void - _onExit?: (type: RouteType, progress: number) => void + _onEnter?: ProgressCallback + _onExit?: ProgressCallback _slide?: SlideEffect _translate?: ArkTranslateParams _scale?: ArkScaleParams diff --git a/arkoala/arkui/src/ArkAnimation.ts b/arkoala/arkui/src/ArkAnimation.ts index 5db389cd3..71fec069d 100644 --- a/arkoala/arkui/src/ArkAnimation.ts +++ b/arkoala/arkui/src/ArkAnimation.ts @@ -32,7 +32,7 @@ export function startImplicitAnimations(param: AnimateParam) { }) console.log("#### ->>>> Animation callback registered: ", methodId) } - nativeModule()._OpenImplicitAnimation(animate.curve, value, methodId) + nativeModule()._OpenImplicitAnimation(value, methodId) } }) } diff --git a/arkoala/arkui/src/ArkPageTransition.ts b/arkoala/arkui/src/ArkPageTransition.ts index 37128274f..28499dda1 100644 --- a/arkoala/arkui/src/ArkPageTransition.ts +++ b/arkoala/arkui/src/ArkPageTransition.ts @@ -13,15 +13,17 @@ * limitations under the License. */ -import { int32 } from "@koalaui/common" +import { float32, int32 } from "@koalaui/common" import { contextNode, remember, scheduleCallback } from "@koalaui/runtime" import { nativeModule, NodePointer, PeerNode, PeerNodeType } from "@koalaui/arkoala" -import { ArkPageTransitionData, ArkPageTransitionEnterComponent, ArkPageTransitionExitComponent, ArkPageTransitionParams, ArkScaleParams, ArkTranslateParams, CurrentRouter, CurrentRouterTransitionState, RouterTransitionVisibility } from "@koalaui/arkui-common" +import { ArkPageTransitionData, ArkPageTransitionEnterComponent, ArkPageTransitionExitComponent, ArkPageTransitionParams, ArkScaleParams, ArkTranslateParams, CurrentRouter, CurrentRouterTransitionState, ProgressCallback, RouterTransitionVisibility } from "@koalaui/arkui-common" import { endImplicitAnimation, startImplicitAnimations } from "./ArkAnimation" import { ArkUIAPIDimensionUnit, parseDimension } from "./shared/basic" -import { Access, withFloat32Array, withInt32Array } from "@koalaui/interop" +import { Access, withFloat32Array, withInt32Array, withString, wrapCallback } from "@koalaui/interop" +import { Deserializer } from "./peers/Deserializer" const ZERO_TRANSLATE = new Float32Array([0, ArkUIAPIDimensionUnit.PX, 0, ArkUIAPIDimensionUnit.PX, 0, ArkUIAPIDimensionUnit.PX]) +const KEY_PAGE_TRANSITION_PROPERTY = "pageTransitionProperty" // See frameworks/core/components_ng/pattern/stage/page_pattern.cpp function translateTransition(ptr: NodePointer, value: ArkTranslateParams) : Float32Array { const xd = parseDimension(value.x, ArkUIAPIDimensionUnit.PX) @@ -83,6 +85,39 @@ function slideTransition(ptr: NodePointer, value: SlideEffect) : Float32Array { return new Float32Array([x, ArkUIAPIDimensionUnit.PX, y, ArkUIAPIDimensionUnit.PX, 0, ArkUIAPIDimensionUnit.PX]) } +function doubleAnimationOptions(startValue: float32, + endValue: float32, + curve: Curve, + duration: number, + delay: number): Float32Array { + return new Float32Array([startValue, endValue, curve, duration, delay]) +} + +function progressCallback(state: RouterTransitionVisibility, + onEnter: ProgressCallback | undefined, + onExit: ProgressCallback | undefined): int32 { + if (state == RouterTransitionVisibility.Hiding && onExit != undefined || + state == RouterTransitionVisibility.Showing && onEnter != undefined) + { + return (state == RouterTransitionVisibility.Hiding && onExit != undefined) ? + wrapCallback((args: Uint8Array, length: int32) => { + const deserializer = new Deserializer(args, length) + const progress = deserializer.readFloat32() + scheduleCallback(() => onExit?.(RouteType.Pop, progress)) + return 0 + }) + : + wrapCallback((args: Uint8Array, length: int32) => { + const deserializer = new Deserializer(args, length) + const progress = deserializer.readFloat32() + scheduleCallback(() => onEnter?.(RouteType.Push, progress)) + return 0 + }) + } else { + return -1 + } +} + /** * @memo */ @@ -100,6 +135,19 @@ function NotifyPageTransition(pageId: int32, style: ArkPageTransitionData, state " scale = ", style._scale, " translate = ", style._translate) + // Start progress animation + const progressCallbackId = progressCallback(state, style._onEnter, style._onExit) + if (progressCallbackId != -1) { + const animationOptions = doubleAnimationOptions(0, 1.0, style.params.curve as Curve, + style.params.duration ?? 0, + style.params.delay ?? 0) + withFloat32Array(animationOptions, Access.READ, options => { + withString(KEY_PAGE_TRANSITION_PROPERTY, propertyName => { + nativeModule()._StartDoubleAnimation(node.getPeerPtr(), progressCallbackId, options, propertyName) + }) + }) + } + if (style._opacity !== undefined) { if (state == RouterTransitionVisibility.Hiding) { nativeModule()._CommonMethod_opacityTransition(node.getPeerPtr(), 1.0) diff --git a/arkoala/arkui/src/shared/basic.ts b/arkoala/arkui/src/shared/basic.ts index 4f277b0cc..0650ad7ad 100644 --- a/arkoala/arkui/src/shared/basic.ts +++ b/arkoala/arkui/src/shared/basic.ts @@ -607,9 +607,8 @@ export function parseListItemGroupStyle(style: ListItemGroupStyle): number { export class ArkAnimate { animateOptions: Float32Array - curve: number constructor(param: AnimateParam) { - this.animateOptions = new Float32Array(5).fill(-1) + this.animateOptions = new Float32Array(6).fill(-1) if (param.duration != undefined) { this.animateOptions[0] = param.duration } @@ -625,7 +624,7 @@ export class ArkAnimate { if (param.playMode != undefined) { this.animateOptions[4] = param.playMode } - this.curve = param.curve ? param.curve as Curve : Curve.EaseInOut + this.animateOptions[5] = param.curve ? param.curve as Curve : Curve.EaseInOut } } diff --git a/arkoala/framework/native/src/arkoala_api.h b/arkoala/framework/native/src/arkoala_api.h index 550435df4..612969428 100644 --- a/arkoala/framework/native/src/arkoala_api.h +++ b/arkoala/framework/native/src/arkoala_api.h @@ -4771,9 +4771,10 @@ struct ArkUINodeContentModifier { struct ArkUIAnimation { ArkUI_Int32 (*startAnimation)(const ArkUIAPIAnimationSpec* spec, ArkUI_Int32 callbackId); - void (*openImplicitAnimation)( - ArkUIVMContext vmContext, ArkUI_Int32 curve, ArkUI_Float32* options, ArkUI_Int32 callbackId); + void (*openImplicitAnimation)(ArkUIVMContext vmContext, ArkUI_Float32* options, ArkUI_Int32 callbackId); void (*closeImplicitAnimation)(); + void (*startDoubleAnimation)(ArkUIVMContext vmContext, ArkUINodeHandle node, ArkUI_Int32 callbackId, + ArkUI_Float32* options, ArkUI_CharPtr propertyName); void (*animateTo)(ArkUIContext* context, ArkUIAnimateOption option, void* event, void* userData); void (*keyframeAnimateTo)(ArkUIContext* context, ArkUIKeyframeAnimateOption* option); ArkUIAnimatorHandle (*createAnimator)(ArkUIContext* context, ArkUIAnimatorOption* option); diff --git a/arkoala/framework/native/src/library.cc b/arkoala/framework/native/src/library.cc index 8f071678b..e5854d40b 100644 --- a/arkoala/framework/native/src/library.cc +++ b/arkoala/framework/native/src/library.cc @@ -3175,12 +3175,20 @@ void impl_CloseImplicitAnimation() { } KOALA_INTEROP_V0(CloseImplicitAnimation) -int impl_OpenImplicitAnimation(KVMContext vmContextPtr, KInt curve, KFloat* options, KInt methodId) { +void impl_OpenImplicitAnimation(KVMContext vmContextPtr, KFloat* options, KInt methodId) { ArkUIVMContext vmContext = reinterpret_cast(vmContextPtr); - GetFullImpl()->getAnimation()->openImplicitAnimation(vmContext, curve, options, methodId); - return 0; + GetFullImpl()->getAnimation()->openImplicitAnimation(vmContext, options, methodId); +} +KOALA_INTEROP_CTX_V2(OpenImplicitAnimation, KFloat*, KInt) + +void impl_StartDoubleAnimation(KVMContext vmContextPtr, KNativePointer nodePtr, KInt callbackId, KFloat* options, + KStringPtr propertyName) +{ + ArkUIVMContext vmContext = reinterpret_cast(vmContextPtr); + ArkUINodeHandle node = reinterpret_cast(nodePtr); + GetFullImpl()->getAnimation()->startDoubleAnimation(vmContext, node, callbackId, options, propertyName); } -KOALA_INTEROP_CTX_3(OpenImplicitAnimation, KInt , KInt, KFloat*, KInt) +KOALA_INTEROP_CTX_V4(StartDoubleAnimation, KInt, KNativePointer, KInt, KFloat*, KStringPtr) //slider void impl_SliderAttribute_showTips(KNativePointer nodePtr, KBoolean isShow, const KStringPtr& valuePtr) { diff --git a/arkoala/framework/src/NativeModule.ts b/arkoala/framework/src/NativeModule.ts index bf04e8785..7c542cf9c 100644 --- a/arkoala/framework/src/NativeModule.ts +++ b/arkoala/framework/src/NativeModule.ts @@ -560,8 +560,9 @@ export interface ComponentOps { _TextAreaController_stopEditing(ptr: NodePointer): void // animation + _OpenImplicitAnimation(options: KFloat32ArrayPtr, onFinish: KInt): KInt _CloseImplicitAnimation(): void - _OpenImplicitAnimation(curve: KInt, options: KFloat32ArrayPtr, onFinish: KInt): KInt + _StartDoubleAnimation(ptr: NodePointer, callbackId: KInt, options: KFloat32ArrayPtr, propertyName: KStringPtr) : void // utilities _ParseDimension(str: KStringPtr, out: KFloat32ArrayPtr): void diff --git a/arkoala/framework/src/NativeModuleEmpty.ts b/arkoala/framework/src/NativeModuleEmpty.ts index 93f3ba889..7689c0ce3 100644 --- a/arkoala/framework/src/NativeModuleEmpty.ts +++ b/arkoala/framework/src/NativeModuleEmpty.ts @@ -672,9 +672,11 @@ export class NativeModuleEmpty extends NativeModuleEmptyIntegrated implements Na _TextAreaAttribute_inputFilter(ptr: NodePointer, value: KStringPtr): void {} _CloseImplicitAnimation(): void {} - _OpenImplicitAnimation(curve: number, options: KFloat32ArrayPtr, onFinish: KInt): number { + _OpenImplicitAnimation(options: KFloat32ArrayPtr, onFinish: KInt): number { return 0 } + _StartDoubleAnimation(ptr: NodePointer, callbackId: KInt, options: KFloat32ArrayPtr, propertyName: KStringPtr) : void {} + _SliderAttribute_showTips(ptr: NodePointer, isShow: KBoolean, value: KStringPtr): void {} _SliderAttribute_optionValue(ptr: NodePointer, value: KFloat): void {} _SliderAttribute_optionValueMin(ptr: NodePointer, value: KInt): void {} diff --git a/interop/src/cpp/ets/convertors-ets.h b/interop/src/cpp/ets/convertors-ets.h index 917d161c1..b3b19750d 100644 --- a/interop/src/cpp/ets/convertors-ets.h +++ b/interop/src/cpp/ets/convertors-ets.h @@ -1188,6 +1188,26 @@ MAKE_ETS_EXPORT(name, "void|" #P0 "|" #P1, ETS_SLOW_NATIVE_FLAG) } \ MAKE_ETS_EXPORT(name, "void|" #P0 "|" #P1 "|" #P2, ETS_SLOW_NATIVE_FLAG) +#define KOALA_INTEROP_CTX_V4(name, P0, P1, P2, P3) \ + void Ark_##name(EtsEnv *env, ets_class clazz, \ + InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, \ + InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3) { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + KVMContext ctx = (KVMContext)env; \ + impl_##name(ctx, p0, p1, p2, p3); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + } \ +MAKE_ETS_EXPORT(name, "void|" #P0 "|" #P1 "|" #P2 "|" #P3, ETS_SLOW_NATIVE_FLAG) + bool setKoalaEtsNapiCallbackDispatcher( EtsEnv* etsEnv, ets_class clazz, diff --git a/interop/src/cpp/jni/convertors-jni.h b/interop/src/cpp/jni/convertors-jni.h index bbb593822..77cd9b04a 100644 --- a/interop/src/cpp/jni/convertors-jni.h +++ b/interop/src/cpp/jni/convertors-jni.h @@ -1276,6 +1276,26 @@ MAKE_JNI_EXPORT(name, "void|" #P0 "|" #P1) } \ MAKE_JNI_EXPORT(name, "void|" #P0 "|" #P1 "|" #P2) +#define KOALA_INTEROP_CTX_V4(name, P0, P1, P2, P3) \ + KOALA_JNI_CALL(void) Java_org_##name(JNIEnv* env, jclass instance, \ + SlowInteropTypeConverter::InteropType _p0, \ + SlowInteropTypeConverter::InteropType _p1, \ + SlowInteropTypeConverter::InteropType _p2, \ + SlowInteropTypeConverter::InteropType _p3) { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + KVMContext ctx = (KVMContext)env; \ + impl_##name(ctx, p0, p1, p2, p3); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ +} \ +MAKE_JNI_EXPORT(name, "void|" #P0 "|" #P1 "|" #P2 "|" #P3) + bool setKoalaJniCallbackDispatcher( JNIEnv* env, jclass clazz, diff --git a/interop/src/cpp/napi/convertors-napi.cc b/interop/src/cpp/napi/convertors-napi.cc index 9406aac14..5c4df8cab 100644 --- a/interop/src/cpp/napi/convertors-napi.cc +++ b/interop/src/cpp/napi/convertors-napi.cc @@ -73,7 +73,7 @@ KStringPtr getString(Napi::Env env, Napi::Value value) { if (value.IsNull() || value.IsUndefined()) { return result; } - +INTEROP_LIBRARY_NAME if (!value.IsString()) { Napi::Error::New(env, "Expected String") .ThrowAsJavaScriptException(); @@ -150,7 +150,7 @@ Napi::Value makeInt32(const Napi::CallbackInfo& info, int32_t value) { } Napi::Value makeUInt32(const Napi::CallbackInfo& info, uint32_t value) { - return Napi::Number::New(info.Env(), value); + return Napi::Number::New(info.Env(), value);INTEROP_LIBRARY_NAME } Napi::Value makeFloat32(const Napi::CallbackInfo& info, float value) { diff --git a/interop/src/cpp/napi/convertors-napi.h b/interop/src/cpp/napi/convertors-napi.h index 05c96a999..b696558b0 100644 --- a/interop/src/cpp/napi/convertors-napi.h +++ b/interop/src/cpp/napi/convertors-napi.h @@ -1003,6 +1003,19 @@ Napi::ModuleRegisterCallback ProvideModuleRegisterCallback(Napi::ModuleRegisterC } \ MAKE_NODE_EXPORT(name) +#define KOALA_INTEROP_CTX_V4(name, P0, P1, P2, P3) \ + Napi::Value Node_##name(const Napi::CallbackInfo& info) { \ + KOALA_MAYBE_LOG(name) \ + KVMContext ctx = reinterpret_cast((napi_env)info.Env()); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + P2 p2 = getArgument(info, 2); \ + P3 p3 = getArgument(info, 3); \ + impl_##name(ctx, p0, p1, p2, p3); \ + return makeVoid(info); \ + } \ + MAKE_NODE_EXPORT(name) + #define NODEJS_GET_AND_THROW_LAST_ERROR(env) \ do { \ const napi_extended_error_info *error_info; \ -- Gitee From 5e6b94a6d50f78330d5981915fe46f70686760eb Mon Sep 17 00:00:00 2001 From: Kirill Kirichenko Date: Tue, 12 Nov 2024 17:41:58 +0300 Subject: [PATCH 6/7] Page transition animation finished Signed-off-by: Kirill Kirichenko --- arkoala/arkui-common/src/Router.ts | 23 ---------------- arkoala/arkui/src/ArkAnimation.ts | 1 - arkoala/arkui/src/ArkComponentRoot.ts | 1 - arkoala/arkui/src/ArkPageTransition.ts | 31 ++++++++++++++-------- arkoala/arkui/src/shared/basic.ts | 4 +++ arkoala/framework/native/src/arkoala_api.h | 4 +-- arkoala/framework/native/src/library.cc | 8 +++--- arkoala/framework/src/NativeModule.ts | 2 +- arkoala/framework/src/NativeModuleEmpty.ts | 2 +- arkoala/framework/src/PeerNode.ts | 2 -- interop/src/cpp/napi/convertors-napi.cc | 3 +-- interop/src/cpp/napi/convertors-napi.h | 2 +- 12 files changed, 34 insertions(+), 49 deletions(-) diff --git a/arkoala/arkui-common/src/Router.ts b/arkoala/arkui-common/src/Router.ts index 5c7edf935..c9abc03d3 100644 --- a/arkoala/arkui-common/src/Router.ts +++ b/arkoala/arkui-common/src/Router.ts @@ -63,7 +63,6 @@ class VisiblePage { setTransitionState(visibility: RouterTransitionVisibility, route?: RouteType) { this.transitionState.value = { pageId: this.version, visibility, route } - console.log(" ^^^^^^^^^^^^ Set visibility state of page = ", this.version, " to ", RouterTransitionVisibility[visibility]) } get transition(): RouterTransitionState { @@ -316,20 +315,6 @@ class RouterImpl implements Router { private pageTransitionMap = new Map>() - private toString(transitions: PageTransition[]): string { - let result = "[ " - transitions.forEach((v, i) => result += (i + ": , ")) - return result + " ]" - } - - private transitionMapString(): string { - let result = "{ " - this.pageTransitionMap.forEach((value, key) => { - result += key + ":" + this.toString(value) + ", " - }) - return result + " }" - } - schedulePageTransition(pageId: int32, transition: PageTransition): void { let queuedTransitions = this.pageTransitionMap.get(pageId) if (queuedTransitions === undefined) { @@ -339,7 +324,6 @@ class RouterImpl implements Router { const length = queuedTransitions.length queuedTransitions.splice(length, 0, transition) - console.log("$$$$$$ ->>>> schedule: pageID=", pageId, " transMap = ", this.transitionMapString()) if (length == 0) { scheduleCallback(transition) @@ -347,8 +331,6 @@ class RouterImpl implements Router { } onPageTransitionEnd(pageId: int32, targetVisibility: RouterTransitionVisibility): void { - console.log("onPageTransitionEnd ", pageId) - const index = this.findIndexByVersion(pageId) if (index >= 0) { const page = this.state.visiblePages[index] @@ -381,15 +363,10 @@ class RouterImpl implements Router { this.pageTransitionMap.delete(pageId) } - console.log("$$$$$$ ->>>> Remove current transition for pageID = ", pageId) if (queuedTransitions.length > 0) { - console.log("$$$$$$ ->>>> Scheduling next transition for pageID = ", pageId) scheduleCallback(queuedTransitions[0]) } - console.log("$$$$$$ ->>>> Transition map = " + this.transitionMapString()) - } else { - console.log("$$$$$$ ->>>> PageTransitionMap for pageID=", pageId, " is empty or undefined") } } diff --git a/arkoala/arkui/src/ArkAnimation.ts b/arkoala/arkui/src/ArkAnimation.ts index 71fec069d..a373b5eec 100644 --- a/arkoala/arkui/src/ArkAnimation.ts +++ b/arkoala/arkui/src/ArkAnimation.ts @@ -30,7 +30,6 @@ export function startImplicitAnimations(param: AnimateParam) { param.onFinish!() return 0 }) - console.log("#### ->>>> Animation callback registered: ", methodId) } nativeModule()._OpenImplicitAnimation(value, methodId) } diff --git a/arkoala/arkui/src/ArkComponentRoot.ts b/arkoala/arkui/src/ArkComponentRoot.ts index 94ea92389..a80096063 100644 --- a/arkoala/arkui/src/ArkComponentRoot.ts +++ b/arkoala/arkui/src/ArkComponentRoot.ts @@ -48,7 +48,6 @@ export function ArkComponentRoot( const state = CurrentRouterTransitionState() if (state) { RunEffect(state.visibility, visibility => { - console.log("#### Page ", state.pageId, " visibility changed to ", RouterTransitionVisibility[visibility]) if (visibility == RouterTransitionVisibility.Showing) component.onPageShow?.() else if (visibility == RouterTransitionVisibility.Hiding) component.onPageHide?.() diff --git a/arkoala/arkui/src/ArkPageTransition.ts b/arkoala/arkui/src/ArkPageTransition.ts index 28499dda1..6cf1925e8 100644 --- a/arkoala/arkui/src/ArkPageTransition.ts +++ b/arkoala/arkui/src/ArkPageTransition.ts @@ -19,7 +19,7 @@ import { nativeModule, NodePointer, PeerNode, PeerNodeType } from "@koalaui/arko import { ArkPageTransitionData, ArkPageTransitionEnterComponent, ArkPageTransitionExitComponent, ArkPageTransitionParams, ArkScaleParams, ArkTranslateParams, CurrentRouter, CurrentRouterTransitionState, ProgressCallback, RouterTransitionVisibility } from "@koalaui/arkui-common" import { endImplicitAnimation, startImplicitAnimations } from "./ArkAnimation" import { ArkUIAPIDimensionUnit, parseDimension } from "./shared/basic" -import { Access, withFloat32Array, withInt32Array, withString, wrapCallback } from "@koalaui/interop" +import { Access, callCallback, disposeCallback, withFloat32Array, withInt32Array, withString, wrapCallback } from "@koalaui/interop" import { Deserializer } from "./peers/Deserializer" const ZERO_TRANSLATE = new Float32Array([0, ArkUIAPIDimensionUnit.PX, 0, ArkUIAPIDimensionUnit.PX, 0, ArkUIAPIDimensionUnit.PX]) @@ -45,13 +45,13 @@ function translateTransition(ptr: NodePointer, value: ArkTranslateParams) : Floa function translateScale(value: ArkScaleParams | undefined = undefined): {values:Float32Array, units: Int32Array } { if (value) { - const centerX = parseDimension(value.centerX ?? 0, ArkUIAPIDimensionUnit.PX) - const centerY = parseDimension(value.centerY ?? 0, ArkUIAPIDimensionUnit.PX) + const centerX = parseDimension(value.centerX ?? 0.5, ArkUIAPIDimensionUnit.PERCENTAGE) + const centerY = parseDimension(value.centerY ?? 0.5, ArkUIAPIDimensionUnit.PERCENTAGE) return {values: new Float32Array([value.x ?? 1.0, value.y ?? 1.0, 1.0, centerX.value, centerY.value]), units: new Int32Array([centerX.unit, centerY.unit])} } else { - return {values: new Float32Array([1.0, 1.0, 1.0, 0.0, 0.0]), - units: new Int32Array([ArkUIAPIDimensionUnit.PX, ArkUIAPIDimensionUnit.PX])} + return {values: new Float32Array([1.0, 1.0, 1.0, 0.5, 0.5]), + units: new Int32Array([ArkUIAPIDimensionUnit.PERCENTAGE, ArkUIAPIDimensionUnit.PERCENTAGE])} } } @@ -101,18 +101,18 @@ function progressCallback(state: RouterTransitionVisibility, { return (state == RouterTransitionVisibility.Hiding && onExit != undefined) ? wrapCallback((args: Uint8Array, length: int32) => { - const deserializer = new Deserializer(args, length) + const deserializer = new Deserializer(args.buffer, length) const progress = deserializer.readFloat32() scheduleCallback(() => onExit?.(RouteType.Pop, progress)) return 0 - }) + }, false) : wrapCallback((args: Uint8Array, length: int32) => { - const deserializer = new Deserializer(args, length) + const deserializer = new Deserializer(args.buffer, length) const progress = deserializer.readFloat32() scheduleCallback(() => onEnter?.(RouteType.Push, progress)) return 0 - }) + }, false) } else { return -1 } @@ -141,9 +141,18 @@ function NotifyPageTransition(pageId: int32, style: ArkPageTransitionData, state const animationOptions = doubleAnimationOptions(0, 1.0, style.params.curve as Curve, style.params.duration ?? 0, style.params.delay ?? 0) + const disposerId = wrapCallback(() => { + disposeCallback(progressCallbackId) + return 0 + }) + + const callbacks = new Int32Array([progressCallbackId, disposerId]) + withFloat32Array(animationOptions, Access.READ, options => { - withString(KEY_PAGE_TRANSITION_PROPERTY, propertyName => { - nativeModule()._StartDoubleAnimation(node.getPeerPtr(), progressCallbackId, options, propertyName) + withInt32Array(callbacks, Access.READ, callbackIds => { + withString(KEY_PAGE_TRANSITION_PROPERTY, propertyName => { + nativeModule()._StartDoubleAnimation(node.getPeerPtr(), callbackIds, options, propertyName) + }) }) }) } diff --git a/arkoala/arkui/src/shared/basic.ts b/arkoala/arkui/src/shared/basic.ts index 0650ad7ad..00df7579e 100644 --- a/arkoala/arkui/src/shared/basic.ts +++ b/arkoala/arkui/src/shared/basic.ts @@ -626,6 +626,10 @@ export class ArkAnimate { } this.animateOptions[5] = param.curve ? param.curve as Curve : Curve.EaseInOut } + + public get curve() { + return this.animateOptions[5] as Curve + } } export interface ChainAnimationOptions { diff --git a/arkoala/framework/native/src/arkoala_api.h b/arkoala/framework/native/src/arkoala_api.h index 612969428..9dd973540 100644 --- a/arkoala/framework/native/src/arkoala_api.h +++ b/arkoala/framework/native/src/arkoala_api.h @@ -4773,8 +4773,8 @@ struct ArkUIAnimation { ArkUI_Int32 (*startAnimation)(const ArkUIAPIAnimationSpec* spec, ArkUI_Int32 callbackId); void (*openImplicitAnimation)(ArkUIVMContext vmContext, ArkUI_Float32* options, ArkUI_Int32 callbackId); void (*closeImplicitAnimation)(); - void (*startDoubleAnimation)(ArkUIVMContext vmContext, ArkUINodeHandle node, ArkUI_Int32 callbackId, - ArkUI_Float32* options, ArkUI_CharPtr propertyName); + void (*startDoubleAnimation)(ArkUIVMContext vmContext, ArkUINodeHandle node, const ArkUI_Int32* callbacks, + const ArkUI_Float32* options, ArkUI_CharPtr propertyName); void (*animateTo)(ArkUIContext* context, ArkUIAnimateOption option, void* event, void* userData); void (*keyframeAnimateTo)(ArkUIContext* context, ArkUIKeyframeAnimateOption* option); ArkUIAnimatorHandle (*createAnimator)(ArkUIContext* context, ArkUIAnimatorOption* option); diff --git a/arkoala/framework/native/src/library.cc b/arkoala/framework/native/src/library.cc index e5854d40b..ede0aff26 100644 --- a/arkoala/framework/native/src/library.cc +++ b/arkoala/framework/native/src/library.cc @@ -3181,14 +3181,14 @@ void impl_OpenImplicitAnimation(KVMContext vmContextPtr, KFloat* options, KInt m } KOALA_INTEROP_CTX_V2(OpenImplicitAnimation, KFloat*, KInt) -void impl_StartDoubleAnimation(KVMContext vmContextPtr, KNativePointer nodePtr, KInt callbackId, KFloat* options, - KStringPtr propertyName) +void impl_StartDoubleAnimation(KVMContext vmContextPtr, KNativePointer nodePtr, KInt* callbacks, KFloat* options, + const KStringPtr& property) { ArkUIVMContext vmContext = reinterpret_cast(vmContextPtr); ArkUINodeHandle node = reinterpret_cast(nodePtr); - GetFullImpl()->getAnimation()->startDoubleAnimation(vmContext, node, callbackId, options, propertyName); + GetFullImpl()->getAnimation()->startDoubleAnimation(vmContext, node, callbacks, options, property.c_str()); } -KOALA_INTEROP_CTX_V4(StartDoubleAnimation, KInt, KNativePointer, KInt, KFloat*, KStringPtr) +KOALA_INTEROP_CTX_V4(StartDoubleAnimation, KNativePointer, KInt*, KFloat*, KStringPtr) //slider void impl_SliderAttribute_showTips(KNativePointer nodePtr, KBoolean isShow, const KStringPtr& valuePtr) { diff --git a/arkoala/framework/src/NativeModule.ts b/arkoala/framework/src/NativeModule.ts index 7c542cf9c..b6ce61873 100644 --- a/arkoala/framework/src/NativeModule.ts +++ b/arkoala/framework/src/NativeModule.ts @@ -562,7 +562,7 @@ export interface ComponentOps { // animation _OpenImplicitAnimation(options: KFloat32ArrayPtr, onFinish: KInt): KInt _CloseImplicitAnimation(): void - _StartDoubleAnimation(ptr: NodePointer, callbackId: KInt, options: KFloat32ArrayPtr, propertyName: KStringPtr) : void + _StartDoubleAnimation(ptr: NodePointer, callbacks: KInt32ArrayPtr, options: KFloat32ArrayPtr, propertyName: KStringPtr) : void // utilities _ParseDimension(str: KStringPtr, out: KFloat32ArrayPtr): void diff --git a/arkoala/framework/src/NativeModuleEmpty.ts b/arkoala/framework/src/NativeModuleEmpty.ts index 7689c0ce3..279776b0b 100644 --- a/arkoala/framework/src/NativeModuleEmpty.ts +++ b/arkoala/framework/src/NativeModuleEmpty.ts @@ -675,7 +675,7 @@ export class NativeModuleEmpty extends NativeModuleEmptyIntegrated implements Na _OpenImplicitAnimation(options: KFloat32ArrayPtr, onFinish: KInt): number { return 0 } - _StartDoubleAnimation(ptr: NodePointer, callbackId: KInt, options: KFloat32ArrayPtr, propertyName: KStringPtr) : void {} + _StartDoubleAnimation(ptr: NodePointer, callbacks: KInt32ArrayPtr, options: KFloat32ArrayPtr, propertyName: KStringPtr) : void {} _SliderAttribute_showTips(ptr: NodePointer, isShow: KBoolean, value: KStringPtr): void {} _SliderAttribute_optionValue(ptr: NodePointer, value: KFloat): void {} diff --git a/arkoala/framework/src/PeerNode.ts b/arkoala/framework/src/PeerNode.ts index 261abeb89..7c6b2f22a 100644 --- a/arkoala/framework/src/PeerNode.ts +++ b/arkoala/framework/src/PeerNode.ts @@ -278,14 +278,12 @@ export class PeerNode extends IncrementalNode implements CustomizableNode { } } - console.log("#### onChildInserted: parent = ", this.peer.toString(), " child = ", peer.peer.toString()) this.peer.insertChildAfter(peer.peer, sibling?.peer) } } this.onChildRemoved = (child: IncrementalNode) => { let peer = findPeerNode(child) if (peer) { - console.log("#### onChildRemoved: parent = ", this.peer.toString(), " child = ", peer.peer.toString()) this.peer.removeChild(peer.peer) } } diff --git a/interop/src/cpp/napi/convertors-napi.cc b/interop/src/cpp/napi/convertors-napi.cc index 5c4df8cab..678de8425 100644 --- a/interop/src/cpp/napi/convertors-napi.cc +++ b/interop/src/cpp/napi/convertors-napi.cc @@ -73,7 +73,6 @@ KStringPtr getString(Napi::Env env, Napi::Value value) { if (value.IsNull() || value.IsUndefined()) { return result; } -INTEROP_LIBRARY_NAME if (!value.IsString()) { Napi::Error::New(env, "Expected String") .ThrowAsJavaScriptException(); @@ -150,7 +149,7 @@ Napi::Value makeInt32(const Napi::CallbackInfo& info, int32_t value) { } Napi::Value makeUInt32(const Napi::CallbackInfo& info, uint32_t value) { - return Napi::Number::New(info.Env(), value);INTEROP_LIBRARY_NAME + return Napi::Number::New(info.Env(), value); } Napi::Value makeFloat32(const Napi::CallbackInfo& info, float value) { diff --git a/interop/src/cpp/napi/convertors-napi.h b/interop/src/cpp/napi/convertors-napi.h index b696558b0..05139fdc8 100644 --- a/interop/src/cpp/napi/convertors-napi.h +++ b/interop/src/cpp/napi/convertors-napi.h @@ -1010,7 +1010,7 @@ Napi::ModuleRegisterCallback ProvideModuleRegisterCallback(Napi::ModuleRegisterC P0 p0 = getArgument(info, 0); \ P1 p1 = getArgument(info, 1); \ P2 p2 = getArgument(info, 2); \ - P3 p3 = getArgument(info, 3); \ + P3 p3 = getArgument(info, 3); \ impl_##name(ctx, p0, p1, p2, p3); \ return makeVoid(info); \ } \ -- Gitee From 4a4a6ebd1b2ed4dd50c4342fcb0cadd0d01d0ca1 Mon Sep 17 00:00:00 2001 From: Kirill Kirichenko Date: Wed, 13 Nov 2024 14:22:38 +0300 Subject: [PATCH 7/7] Remove trailing whitespaces Signed-off-by: Kirill Kirichenko --- arkoala/arkui/src/ArkPageTransition.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arkoala/arkui/src/ArkPageTransition.ts b/arkoala/arkui/src/ArkPageTransition.ts index 6cf1925e8..b28d7552f 100644 --- a/arkoala/arkui/src/ArkPageTransition.ts +++ b/arkoala/arkui/src/ArkPageTransition.ts @@ -96,7 +96,7 @@ function doubleAnimationOptions(startValue: float32, function progressCallback(state: RouterTransitionVisibility, onEnter: ProgressCallback | undefined, onExit: ProgressCallback | undefined): int32 { - if (state == RouterTransitionVisibility.Hiding && onExit != undefined || + if (state == RouterTransitionVisibility.Hiding && onExit != undefined || state == RouterTransitionVisibility.Showing && onEnter != undefined) { return (state == RouterTransitionVisibility.Hiding && onExit != undefined) ? @@ -130,7 +130,7 @@ function NotifyPageTransition(pageId: int32, style: ArkPageTransitionData, state " curve = ", style.params.curve === undefined || (typeof style.params.curve === "string") ? style.params.curve : Curve[style.params.curve], " delay = ", style.params.delay, " state = ", RouterTransitionVisibility[state], - " opacity = ", style._opacity, + " opacity = ", style._opacity, " slide = ", style._slide !== undefined ? SlideEffect[style._slide] : "undefined", " scale = ", style._scale, " translate = ", style._translate) @@ -163,7 +163,7 @@ function NotifyPageTransition(pageId: int32, style: ArkPageTransitionData, state } else if (state == RouterTransitionVisibility.Showing) { nativeModule()._CommonMethod_opacityTransition(node.getPeerPtr(), style._opacity) } - } + } if (style._slide !== undefined || style._translate !== undefined || style._scale !== undefined) { if (state == RouterTransitionVisibility.Hiding) { @@ -186,7 +186,7 @@ function NotifyPageTransition(pageId: int32, style: ArkPageTransitionData, state }) }) } - + if (style._slide !== undefined) { const translate = slideTransition(node.getPeerPtr(), style._slide) withFloat32Array(translate, Access.READ, tr => @@ -214,7 +214,7 @@ function NotifyPageTransition(pageId: int32, style: ArkPageTransitionData, state } else if (state == RouterTransitionVisibility.Showing) { nativeModule()._CommonMethod_opacityTransition(node.getPeerPtr(), 1.0) } - } + } if (style._slide !== undefined || style._translate !== undefined || style._scale !== undefined) { if (state == RouterTransitionVisibility.Hiding) { @@ -226,7 +226,7 @@ function NotifyPageTransition(pageId: int32, style: ArkPageTransitionData, state }) }) } - + if (style._slide !== undefined) { const translate = slideTransition(node.getPeerPtr(), style._slide) withFloat32Array(translate, Access.READ, tr => -- Gitee