diff --git a/arkoala/arkui-common/src/ArkPageTransition.ts b/arkoala/arkui-common/src/ArkPageTransition.ts index e34d443aa38b7176f65ab3d0932ea195c908e851..4e7897d2b75ef523599eaf89c216b39226b459d4 100644 --- a/arkoala/arkui-common/src/ArkPageTransition.ts +++ b/arkoala/arkui-common/src/ArkPageTransition.ts @@ -20,13 +20,29 @@ 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 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?: { 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 +60,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-common/src/Router.ts b/arkoala/arkui-common/src/Router.ts index a3352297adc018d0683f12fe98c28e07a9f25004..c9abc03d3d375935b4406334bcbab62f7e540d57 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" @@ -120,6 +121,8 @@ export class PageInfo { constructor(public depth: number, public page: string) { } } +export type PageTransition = () => void + /** * Interface providing page routing functionality. */ @@ -196,7 +199,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 +313,60 @@ class RouterImpl implements Router { return -1 } - onPageTransitionEnd(pageId: int32): void { + private pageTransitionMap = new Map>() + + 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) + + if (length == 0) { + scheduleCallback(transition) + } + } + + onPageTransitionEnd(pageId: int32, targetVisibility: RouterTransitionVisibility): void { 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) + + if (queuedTransitions.length > 0) { + scheduleCallback(queuedTransitions[0]) } - } else { - console.log("ERROR: no page transition:", RouterTransitionVisibility[page.transition.visibility], page.transition.route ? RouteType[page.transition.route] : "unknown") + } } diff --git a/arkoala/arkui/docs/Animation_issues.md b/arkoala/arkui/docs/Animation_issues.md new file mode 100644 index 0000000000000000000000000000000000000000..a1f5c607783ba2165d263ac25d84c98fbe2776ab --- /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 0000000000000000000000000000000000000000..935141dda00aac85280997b0ff64511f577de688 --- /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 0000000000000000000000000000000000000000..2bd5ca2a0dfcc711754ede750d2c223e26ad8d18 --- /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 diff --git a/arkoala/arkui/src/ArkAnimation.ts b/arkoala/arkui/src/ArkAnimation.ts index 13a17a357b9835698e00a2be7d30a1346cdc2637..a373b5eec7a004a01b4a0a25f6d939b4ebf1d824 100644 --- a/arkoala/arkui/src/ArkAnimation.ts +++ b/arkoala/arkui/src/ArkAnimation.ts @@ -31,7 +31,7 @@ export function startImplicitAnimations(param: AnimateParam) { return 0 }) } - nativeModule()._OpenImplicitAnimation(animate.curve, value, methodId) + nativeModule()._OpenImplicitAnimation(value, methodId) } }) } diff --git a/arkoala/arkui/src/ArkCommon.ts b/arkoala/arkui/src/ArkCommon.ts index b59f8f4cc10ad513a1d51a35ea5f8c8754796a1f..bde869b91efa0a1bef6bd719dfc5a6620da009b2 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 9971e22bcebd17fa6d386c03a3255a2dd50c6574..a80096063a6942d162be2c98014220f242d576f6 100644 --- a/arkoala/arkui/src/ArkComponentRoot.ts +++ b/arkoala/arkui/src/ArkComponentRoot.ts @@ -48,6 +48,7 @@ export function ArkComponentRoot( const state = CurrentRouterTransitionState() if (state) { RunEffect(state.visibility, 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 3beda5cc375ce4ee357abf83cda9821666d42901..b28d7552fd7248296ffc7b7f0096a6b9d9fd2484 100644 --- a/arkoala/arkui/src/ArkPageTransition.ts +++ b/arkoala/arkui/src/ArkPageTransition.ts @@ -13,28 +13,245 @@ * limitations under the License. */ -import { int32 } from "@koalaui/common" +import { float32, 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, ArkScaleParams, ArkTranslateParams, CurrentRouter, CurrentRouterTransitionState, ProgressCallback, RouterTransitionVisibility } from "@koalaui/arkui-common" +import { endImplicitAnimation, startImplicitAnimations } from "./ArkAnimation" +import { ArkUIAPIDimensionUnit, parseDimension } from "./shared/basic" +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]) +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) + 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]) +} + +function translateScale(value: ArkScaleParams | undefined = undefined): {values:Float32Array, units: Int32Array } { + if (value) { + 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.5, 0.5]), + units: new Int32Array([ArkUIAPIDimensionUnit.PERCENTAGE, ArkUIAPIDimensionUnit.PERCENTAGE])} + } +} + +// 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]) +} + +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.buffer, length) + const progress = deserializer.readFloat32() + scheduleCallback(() => onExit?.(RouteType.Pop, progress)) + return 0 + }, false) + : + wrapCallback((args: Uint8Array, length: int32) => { + const deserializer = new Deserializer(args.buffer, length) + const progress = deserializer.readFloat32() + scheduleCallback(() => onEnter?.(RouteType.Push, progress)) + return 0 + }, false) + } else { + return -1 + } +} /** * @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) + 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, + " state = ", RouterTransitionVisibility[state], + " opacity = ", style._opacity, + " slide = ", style._slide !== undefined ? SlideEffect[style._slide] : "undefined", + " 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) + const disposerId = wrapCallback(() => { + disposeCallback(progressCallbackId) + return 0 + }) + + const callbacks = new Int32Array([progressCallbackId, disposerId]) + + withFloat32Array(animationOptions, Access.READ, options => { + withInt32Array(callbacks, Access.READ, callbackIds => { + withString(KEY_PAGE_TRANSITION_PROPERTY, propertyName => { + nativeModule()._StartDoubleAnimation(node.getPeerPtr(), callbackIds, options, propertyName) + }) + }) + }) + } + + 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 || style._scale !== undefined) { + if (state == RouterTransitionVisibility.Hiding) { + 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) { + 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)) + } else if (style._translate !== undefined) { + const translate = translateTransition(node.getPeerPtr(), style._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: () => router?.onPageTransitionEnd(pageId, state) + }) + + 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 || style._scale !== undefined) { + if (state == RouterTransitionVisibility.Hiding) { + 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) { + 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)) + } + } + + nativeModule()._SetClipRect(node.getPeerPtr(), 0, 0, 10000, 10000) + + endImplicitAnimation() }) } @@ -43,12 +260,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 +277,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 af4a565c99a5060fab2919a9393d3de1be69f973..5f3248abbeee5cb10e4e124a492d8de2bd37baec 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 b05842a1065322d8b8087a6ab2308fb8ac0e10d4..919ca9e6f6692903fb2a61ed4b8e0b3f07e5b7e3 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 cd4ab2d4c83be14a51f347a3bd7605d2c74f9904..8619288c477e0e33f0caaa8b2ec1b29c91715ed0 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 9afad0d7fe5ca390541d6786a4476d06366e4cba..00df7579eb3ffff72c2a6577f8d4a4751125ee76 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) } @@ -608,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 } @@ -626,7 +624,11 @@ 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 + } + + public get curve() { + return this.animateOptions[5] as Curve } } diff --git a/arkoala/framework/native/src/arkoala_api.h b/arkoala/framework/native/src/arkoala_api.h index a9f88b47f62c3c715eb809787996c5fc66e9494b..9dd973540063777054948e9199ffbfba02c6257a 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, 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); @@ -5125,6 +5126,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 84bb612597eb862a44637d4dce086041f2789546..ede0aff26c549750be0e9f341196119d373614f9 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); @@ -3150,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* callbacks, KFloat* options, + const KStringPtr& property) +{ + ArkUIVMContext vmContext = reinterpret_cast(vmContextPtr); + ArkUINodeHandle node = reinterpret_cast(nodePtr); + GetFullImpl()->getAnimation()->startDoubleAnimation(vmContext, node, callbacks, options, property.c_str()); } -KOALA_INTEROP_CTX_3(OpenImplicitAnimation, KInt , KInt, KFloat*, KInt) +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 2c4db0ebda068964402eef00fd50ea3ee0aa0b89..b6ce61873f5214931f6f0a7982fbdd2afed83e2f 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 @@ -557,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, 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 7c55ed41c92a9be60ff330a34f4da33fbdda1b20..279776b0bc69fba324fff334abbd0fa8e1273ba3 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 @@ -669,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, callbacks: KInt32ArrayPtr, 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/arkoala/framework/src/PeerNode.ts b/arkoala/framework/src/PeerNode.ts index 27e33c0215052784d28aafc0284fdc19b0b83f02..7c6b2f22a56a19bf5d5eae171cbd24018ac7a0b2 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,6 +277,7 @@ export class PeerNode extends IncrementalNode implements CustomizableNode { break } } + this.peer.insertChildAfter(peer.peer, sibling?.peer) } } diff --git a/interop/src/cpp/ets/convertors-ets.h b/interop/src/cpp/ets/convertors-ets.h index 917d161c1980f7f537fadacf71f7c4554655f6b3..b3b19750d16a2f464bc2aed09c09839ae953a481 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 bbb59382252caa45a882ab75bcea7ee93c22bd41..77cd9b04aabbeebc7e9c7f665f25d745cdf0c412 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 9406aac143eded0ae55f02a792335eb09f225d32..678de84250e92b53cc847842806cb8e32294fdb5 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; } - if (!value.IsString()) { Napi::Error::New(env, "Expected String") .ThrowAsJavaScriptException(); diff --git a/interop/src/cpp/napi/convertors-napi.h b/interop/src/cpp/napi/convertors-napi.h index 05c96a999a66c2586a3bb1253283c9e0159b8faa..05139fdc8d801d40c9fc49c387a2a1c3aa7791db 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; \