From a91fc0092c82fd42fbd40f5a6326b8d473a92a9a Mon Sep 17 00:00:00 2001 From: sun-xinyan Date: Tue, 9 Sep 2025 16:48:42 +0800 Subject: [PATCH] navigation hook function Signed-off-by: sun-xinyan Change-Id: I8a64233ca4a6707cb94b0493c942955ef87731ad --- .../generated/component/navigation.ets | 62 ++--- .../arkui-ohos/src/base/ArkNavPathStack.ets | 256 +++++++++++++++++- .../arkui-ohos/src/hooks/index.ets | 31 +++ 3 files changed, 299 insertions(+), 50 deletions(-) diff --git a/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/generated/component/navigation.ets b/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/generated/component/navigation.ets index 96ce599a303..4192adaeeb9 100644 --- a/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/generated/component/navigation.ets +++ b/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/generated/component/navigation.ets @@ -29,7 +29,7 @@ import { window_SystemBarStyle_serializer } from "./../framework/ohos.window" import { ComponentBase } from "./../ComponentBase" import { PeerNode } from "./../PeerNode" import { Resource } from "global.resource" -import { extractors, AttributeModifier, hookNavigationAttributeModifier, AttributeUpdater } from "#handwritten" +import { hookPushPathMethod, hookPushPathByNameMethod, hookReplacePathMethod, hookReplacePathByNameMethod, hookPopMethod, hookPopToNameMethod, hookPopToIndexMethod, hookGetParamByIndexMethod, hookGetParamByNameMethod, extractors, AttributeModifier, hookNavigationAttributeModifier, AttributeUpdater } from "#handwritten" import { default as image } from "@ohos.multimedia.image" import { SymbolGlyphModifier } from "arkui.SymbolGlyphModifier" import { CustomBuilder, PageMapBuilder } from "./builder" @@ -49,6 +49,7 @@ import { NavigationModifier } from "./../NavigationModifier" import { NodeAttach, remember } from "@koalaui/runtime" import { LengthMetrics_serializer } from "./../Graphics" import { TextModifier_serializer } from "./../TextModifier" +import { PathStackUtils } from "../base/ArkNavPathStack" export interface NavigationTransitionProxy { from: NavContentInfo to: NavContentInfo @@ -395,6 +396,11 @@ export class NavPathInfo implements MaterializedBase { this.setNavDestinationId_serialize(navDestinationId_casted) return } + updateNavPathInfo(): void { + this.setName_serialize(this.name) + this.setIsEntry_serialize(this.isEntry!) + this.setNavDestinationId_serialize(this.navDestinationId!) + } private getName_serialize(): string { const retval = ArkUIGeneratedNativeModule._NavPathInfo_getName(this.peer!.ptr) return retval @@ -531,15 +537,11 @@ export class NavPathStack implements MaterializedBase { return ArkUIGeneratedNativeModule._NavPathStack_getFinalizer() } public pushPath(info: NavPathInfo, animated?: boolean): void { - const info_casted = info as (NavPathInfo) - const animated_casted = animated as (boolean | undefined) - this.pushPath0_serialize(info_casted, animated_casted) + hookPushPathMethod(this, info, animated); return } public pushPath(info: NavPathInfo, options?: NavigationOptions): void { - const info_casted = info as (NavPathInfo) - const options_casted = options as (NavigationOptions | undefined) - this.pushPath1_serialize(info_casted, options_casted) + hookPushPathMethod(this, info, options); return } public pushDestination(info: NavPathInfo, animated?: boolean): Promise { @@ -553,18 +555,11 @@ export class NavPathStack implements MaterializedBase { return this.pushDestination1_serialize(info_casted, options_casted) } public pushPathByName(name: string, param: Object | null | undefined, animated?: boolean): void { - const name_casted = name as (string) - const param_casted = param as (Object | null | undefined) - const animated_casted = animated as (boolean | undefined) - this.pushPathByName0_serialize(name_casted, param_casted, animated_casted) + hookPushPathByNameMethod(this, name, param, animated); return } public pushPathByName(name: string, param: Object, onPop: ((value0: PopInfo) => void), animated?: boolean): void { - const name_casted = name as (string) - const param_casted = param as (Object) - const onPop_casted = onPop as (((value0: PopInfo) => void)) - const animated_casted = animated as (boolean | undefined) - this.pushPathByName1_serialize(name_casted, param_casted, onPop_casted, animated_casted) + hookPushPathByNameMethod(this, name, param, onPop, animated); return } public pushDestinationByName(name: string, param: Object, animated?: boolean): Promise { @@ -581,15 +576,11 @@ export class NavPathStack implements MaterializedBase { return this.pushDestinationByName1_serialize(name_casted, param_casted, onPop_casted, animated_casted) } public replacePath(info: NavPathInfo, animated?: boolean): void { - const info_casted = info as (NavPathInfo) - const animated_casted = animated as (boolean | undefined) - this.replacePath0_serialize(info_casted, animated_casted) + hookReplacePathMethod(this, info, animated); return } public replacePath(info: NavPathInfo, options?: NavigationOptions): void { - const info_casted = info as (NavPathInfo) - const options_casted = options as (NavigationOptions | undefined) - this.replacePath1_serialize(info_casted, options_casted) + hookReplacePathMethod(this, info, options); return } public replaceDestination(info: NavPathInfo, options?: NavigationOptions): Promise { @@ -598,10 +589,7 @@ export class NavPathStack implements MaterializedBase { return this.replaceDestination_serialize(info_casted, options_casted) } public replacePathByName(name: string, param: Object, animated?: boolean): void { - const name_casted = name as (string) - const param_casted = param as (Object) - const animated_casted = animated as (boolean | undefined) - this.replacePathByName_serialize(name_casted, param_casted, animated_casted) + hookReplacePathByNameMethod(this, name, param, animated); return } public removeByIndexes(indexes: Array): number { @@ -617,13 +605,10 @@ export class NavPathStack implements MaterializedBase { return this.removeByNavDestinationId_serialize(navDestinationId_casted) } public pop(animated?: boolean): NavPathInfo | undefined { - const animated_casted = animated as (boolean | undefined) - return this.pop0_serialize(animated_casted) + return hookPopMethod(this, animated); } public pop(result: Object, animated?: boolean): NavPathInfo | undefined { - const result_casted = result as (Object) - const animated_casted = animated as (boolean | undefined) - return this.pop1_serialize(result_casted, animated_casted) + return hookPopMethod(this, result, animated); } public popToName(name: string, animated?: boolean): number { const name_casted = name as (string) @@ -637,16 +622,11 @@ export class NavPathStack implements MaterializedBase { return this.popToName1_serialize(name_casted, result_casted, animated_casted) } public popToIndex(index: number, animated?: boolean): void { - const index_casted = index as (number) - const animated_casted = animated as (boolean | undefined) - this.popToIndex0_serialize(index_casted, animated_casted) + hookPopToIndexMethod(this, index, animated); return } public popToIndex(index: number, result: Object, animated?: boolean): void { - const index_casted = index as (number) - const result_casted = result as (Object) - const animated_casted = animated as (boolean | undefined) - this.popToIndex1_serialize(index_casted, result_casted, animated_casted) + hookPopToIndexMethod(this, index, result, animated); return } public moveToTop(name: string, animated?: boolean): number { @@ -669,12 +649,10 @@ export class NavPathStack implements MaterializedBase { return this.getAllPathName_serialize() } public getParamByIndex(index: number): Object | null | undefined { - const index_casted = index as (number) - return this.getParamByIndex_serialize(index_casted) + return hookGetParamByIndexMethod(this, index); } public getParamByName(name: string): Array { - const name_casted = name as (string) - return this.getParamByName_serialize(name_casted) + return hookGetParamByNameMethod(this, name); } public getIndexByName(name: string): Array { const name_casted = name as (string) diff --git a/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/base/ArkNavPathStack.ets b/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/base/ArkNavPathStack.ets index c4912da136c..a59ce5f625d 100644 --- a/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/base/ArkNavPathStack.ets +++ b/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/base/ArkNavPathStack.ets @@ -13,14 +13,254 @@ * limitations under the License. */ -export class PathData { - readonly name: string - readonly param: Array = new Array() - constructor(name: string, param: object | undefined) { - this.name = name - if (param !== undefined) { - this.param.push(param!) +import { InteropNativeModule } from '@koalaui/interop' +import { int32 } from "@koalaui/common" +import { LaunchMode, NavPathInfo, NavPathStack, NavigationOptions, PopInfo } from "../component/navigation" +import { NavExtender } from "../component/idlize" + +export class PathStackUtils { + static id: number = 0 + static result: object | undefined = undefined + private static infoMaps: Map = new Map() + private static infoArray: Array = new Array() + static getParamByNavDestinationId(navDestinationId: string): Object | null | undefined { + if (PathStackUtils.infoMaps.has(navDestinationId)) { + return PathStackUtils.infoMaps.get(navDestinationId)!.param; + } + return undefined + } + static addNavPathInfo(info: NavPathInfo, launchMode: LaunchMode, isReplace: boolean = false): void { + if (launchMode === LaunchMode.MOVE_TO_TOP_SINGLETON) { + let index = PathStackUtils.infoArray.findIndex(element => element.name === info.name) as int32 + if (index !== -1) { + PathStackUtils.infoArray[index] = info + let targetInfo = PathStackUtils.infoArray.splice(index, 1) + if (isReplace) { + let popInfo = PathStackUtils.infoArray.pop() + if (popInfo !== undefined && popInfo!.navDestinationId != undefined) { + PathStackUtils.infoMaps.delete(popInfo?.navDestinationId!) + } + } + PathStackUtils.infoArray.push(targetInfo[0]) + } + return + } else if (launchMode === LaunchMode.POP_TO_SINGLETON) { + let index = PathStackUtils.infoArray.findIndex(element => element.name === info.name) as int32 + if (index != -1) { + PathStackUtils.infoArray[index] = info + if (isReplace) { + let targetInfo = PathStackUtils.infoArray.splice(index, 1) + let deletedInfos = PathStackUtils.infoArray.splice(index) + deletedInfos.forEach((element) => { + if (element.navDestinationId != undefined) { + PathStackUtils.infoMaps.delete(element.navDestinationId!) + } + }) + PathStackUtils.infoArray.push(targetInfo[0]) + } else { + let deletedInfos = PathStackUtils.infoArray.splice(index + 1) + deletedInfos.forEach((element) => { + if (element.navDestinationId != undefined) { + PathStackUtils.infoMaps.delete(element.navDestinationId!) + } + }) + } + } + return + } + const navDestinationId: string = "" + PathStackUtils.id + info.navDestinationId = navDestinationId + if (isReplace) { + let popInfo = PathStackUtils.infoArray.pop() + if (popInfo !== undefined) { + let prenavDestinationId = popInfo.navDestinationId + if (prenavDestinationId !== undefined && PathStackUtils.infoMaps.has(prenavDestinationId)) { + PathStackUtils.infoMaps.delete(prenavDestinationId!) + } + } + } + PathStackUtils.infoMaps.set(navDestinationId, info) + PathStackUtils.infoArray.push(info) + PathStackUtils.id++; + info.updateNavPathInfo() + } + static getNavPathInfoById(navDestinationId: string): NavPathInfo | undefined { + if (PathStackUtils.infoMaps.has(navDestinationId)) { + return PathStackUtils.infoMaps.get(navDestinationId) + } + return undefined + } + static popPage(indexOrId?: number | string) { + try { + let id: string | undefined = '' + if (typeof indexOrId === 'string') { + id = indexOrId as string + let navId = indexOrId as string + let index = PathStackUtils.infoArray.findIndex(element => element.navDestinationId === navId) + if (index != -1) { + PathStackUtils.infoArray.splice(index, 1) + } + } else if (typeof indexOrId === 'number') { + let inputIndex = indexOrId as number; + if (inputIndex < 0 || inputIndex >= PathStackUtils.infoArray.length) { + return; + } + id = PathStackUtils.infoArray[PathStackUtils.infoArray.length - 1].navDestinationId; + let removeArray = PathStackUtils.infoArray.splice(inputIndex + 1); + removeArray.forEach((element) => { + if (element.navDestinationId != undefined && element.navDestinationId == id) { + PathStackUtils.infoMaps.delete(element.navDestinationId!) + } + }) + } else { + indexOrId = PathStackUtils.infoArray.length - 1 + id = PathStackUtils.infoArray[PathStackUtils.infoArray.length - 1].navDestinationId + PathStackUtils.infoArray.splice(PathStackUtils.infoArray.length - 1, 1) + } + if (typeof id === 'string') { + PathStackUtils.callOnPop(id!) + } + } catch (error) { + InteropNativeModule._NativeLog("AceNavigation::popPage error: " + error) + } + + } + static callOnPop(navDestinationId: string) { + try { + if (PathStackUtils.infoMaps.has(navDestinationId)) { + let info = PathStackUtils.infoMaps.get(navDestinationId) + if (info != undefined) { + let callback = info!.onPop + if (callback != undefined && info != undefined && PathStackUtils.result != undefined) { + let popInfo: PopInfo = { info: info, result: PathStackUtils.result!} + callback(popInfo) + } + } + PathStackUtils.infoMaps.delete(navDestinationId) + } + } catch (error) { + InteropNativeModule._NativeLog("AceNavigation::callOnPop error:" + error) + } + } + static pushPath(pathStack: NavPathStack, info: NavPathInfo, animated?: boolean | undefined | NavigationOptions | undefined): void { + let options: NavigationOptions = {animated: true, launchMode: LaunchMode.STANDARD} + if (typeof animated === "boolean") { + options.animated = animated as boolean + } else if (animated instanceof NavigationOptions) { + let userSetOptions = animated as NavigationOptions + if (userSetOptions.animated !== undefined) { + options.animated = userSetOptions.animated + } + if (userSetOptions.launchMode !== undefined) { + options.launchMode = userSetOptions.launchMode + } + } + PathStackUtils.addNavPathInfo(info, options.launchMode!) + NavExtender.pushPath(pathStack, info, options) + } + + static pushPathByName(pathStack: NavPathStack, name: string, param: Object | null | undefined, onPop?: ((parameter: PopInfo) => void) | boolean | undefined, animated?: boolean): void { + if (typeof onPop === "boolean" || onPop === undefined) { + const animate_cast = onPop as (boolean | undefined) + let pathInfo: NavPathInfo = new NavPathInfo(name, param) + PathStackUtils.pushPath(pathStack, pathInfo, animate_cast) + return + } + let onPop_casted = onPop as ((parameter: PopInfo) => void) + let pathInfo: NavPathInfo = new NavPathInfo(name, param, onPop_casted, false) + PathStackUtils.pushPath(pathStack, pathInfo, animated) + } + + static replacePath(pathStack: NavPathStack, info: NavPathInfo, animated?: boolean | NavigationOptions | undefined): void { + let options: NavigationOptions = {animated: true, launchMode: LaunchMode.STANDARD} + if (typeof animated === "boolean") { + options.animated = animated as boolean + } else if (animated instanceof NavigationOptions) { + let userSetOptions = animated as NavigationOptions + if (userSetOptions.animated !== undefined) { + options.animated = userSetOptions.animated + } + if (userSetOptions.launchMode !== undefined) { + options.launchMode = userSetOptions.launchMode + } + } + PathStackUtils.addNavPathInfo(info, options.launchMode!, true) + NavExtender.replacePath(pathStack, info, options) + } + + static replacePathByName(pathStack: NavPathStack, name: string, param: Object, animated?: boolean): void { + let pathInfo: NavPathInfo = new NavPathInfo(name, param) + PathStackUtils.replacePath(pathStack, pathInfo, animated) + } + + static pop(pathStack: NavPathStack, result?: boolean | undefined | Object, animated?: boolean): NavPathInfo | undefined + { + if (result instanceof Object) { + PathStackUtils.result = result as Object + } + let animated_value: boolean = true + if (typeof result === "boolean") { + animated_value = result as (boolean) + } + if (typeof animated === "boolean") { + animated_value = animated! + } + const retval = NavExtender.pop(pathStack, animated_value) + const pathInfo = PathStackUtils.getNavPathInfoById(retval) + PathStackUtils.popPage(retval) + return pathInfo + } + static getParamByIndex(pathStack: NavPathStack, index: number): Object | undefined { + const navDestinationId: string = NavExtender.getIdByIndex(pathStack, index as (int32)); + let pathInfo = PathStackUtils.getNavPathInfoById(navDestinationId) + if (pathInfo?.param === null) { + return undefined + } + return pathInfo?.param as Object | undefined + } + static getParamByName(pathStack: NavPathStack, name: string): Array { + let result: Array = new Array() + let ids = NavExtender.getIdByName(pathStack, name) + for (let index = 0; index < ids.length; index++) { + if (!PathStackUtils.infoMaps.has(ids[index])) { + result.push(undefined) + continue + } + let info = PathStackUtils.infoMaps.get(ids[index]) + if (info && info.param) { + result.push(info!.param!) + } + } + return result + } + static popToIndex(pathStack: NavPathStack, index: number, result?: boolean | undefined | Object, animated?: boolean) { + if (result instanceof Object) { + PathStackUtils.result = result as Object + } + let animated_value: boolean = true + if (typeof result === "boolean") { + animated_value = result as boolean + } + if (typeof animated === "boolean") { + animated_value = animated as boolean + } + const index_casted = index as int32 + PathStackUtils.popPage(index_casted) + NavExtender.popToIndex(pathStack, index_casted, animated_value) + } + static popToName(pathStack: NavPathStack, name: string, result?: boolean | undefined | Object, animated?: boolean): number { + if (result instanceof Object) { + PathStackUtils.result = result as Object + } + let animated_value: boolean = true + if (typeof result === "boolean") { + animated_value = result as boolean + } + if (typeof animated === "boolean") { + animated_value = animated as boolean } + let index = NavExtender.popToName(pathStack, name, animated_value) + PathStackUtils.popPage(index) + return index } - static readonly EMPTY: PathData = new PathData("", undefined) } \ No newline at end of file diff --git a/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/hooks/index.ets b/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/hooks/index.ets index 2206ad38573..904f8f88452 100644 --- a/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/hooks/index.ets +++ b/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/hooks/index.ets @@ -63,6 +63,8 @@ import { ArkTextClockComponent, TextClockConfiguration } from "#generated"; import { ArkTextTimerComponent, TextTimerConfiguration } from "#generated"; import { ArkToggleComponent, ToggleConfiguration, ContentModifier, GestureModifier } from "#generated"; import { pointer } from "@koalaui/interop"; +import { NavPathStack, NavPathInfo, NavigationOptions, PopInfo } from "../component/navigation" +import { PathStackUtils } from "../base/ArkNavPathStack" export function hookCheckBoxContentModifier( receiver: ArkCheckboxComponent, @@ -113,3 +115,32 @@ export function hookCustomPropertyImpl(component: ArkCommonMethodComponent, name export * from "./modifiers"; export * from "./content_modifiers/ContentModifierHooks"; + +export function hookPushPathMethod(pathStack: NavPathStack, info: NavPathInfo, animated?: boolean | NavigationOptions | undefined): void { + PathStackUtils.pushPath(pathStack, info, animated); +} + +export function hookPushPathByNameMethod(pathStack: NavPathStack, name: string, param: Object | null | undefined, onPop?: ((parameter: PopInfo) => void) | boolean | undefined, animated?: boolean): void { + PathStackUtils.pushPathByName(pathStack, name, param, onPop, animated); +} +export function hookReplacePathMethod(pathStack: NavPathStack, info: NavPathInfo, animated?: boolean | NavigationOptions | undefined): void { + PathStackUtils.replacePath(pathStack, info, animated); +} +export function hookReplacePathByNameMethod(pathStack: NavPathStack, name: string, param: Object, animated?: boolean): void { + PathStackUtils.replacePathByName(pathStack, name, param, animated); +} +export function hookPopMethod(pathStack: NavPathStack, result?: boolean | undefined | Object, animated?: boolean): NavPathInfo | undefined { + return PathStackUtils.pop(pathStack, result, animated); +} +export function hookPopToNameMethod(pathStack: NavPathStack, name: string, result?: boolean | undefined | Object, animated?: boolean): number { + return PathStackUtils.popToName(pathStack, name, result, animated); +} +export function hookPopToIndexMethod(pathStack: NavPathStack, index: number, result?: boolean | undefined | Object, animated?: boolean) { + PathStackUtils.popToIndex(pathStack, index, result, animated); +} +export function hookGetParamByIndexMethod(pathStack: NavPathStack, index: number): Object | undefined { + return PathStackUtils.getParamByIndex(pathStack, index); +} +export function hookGetParamByNameMethod(pathStack: NavPathStack, name: string): Array { + return PathStackUtils.getParamByName(pathStack, name); +} \ No newline at end of file -- Gitee