Allow OHOS servoshell to have a simple multiple tab implementation. (#36891)

Currently we just pause the compositor and replace the window in it
while having separate bookkeeping to remember which window belongs to
which tab.
Currently there are no tests for OHOS, so we cannot test the changes.

---------

Signed-off-by: Narfinger <Narfinger@users.noreply.github.com>
Co-authored-by: Jonathan Schwender <55576758+jschwe@users.noreply.github.com>
This commit is contained in:
Narfinger 2025-06-16 10:17:31 +02:00 committed by GitHub
parent 71bf9fb92d
commit 3b73b83a9f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 245 additions and 87 deletions

View file

@ -5,11 +5,18 @@ import promptAction from '@ohos.promptAction';
interface ServoXComponentInterface {
loadURL(url: string): void;
goBack(): void;
goForward(): void;
registerURLcallback(callback: (url: string) => void): void;
registerTerminateCallback(callback: () => void): void;
registerPromptToastCallback(callback: (msg: string) => void): void
focusWebview(index: number):void;
initServo(options: InitOpts): void;
}
@ -20,10 +27,10 @@ interface InitOpts {
}
function prompt_toast(msg: string) {
promptAction.showToast({
message: msg,
duration: 2000
});
promptAction.showToast({
message: msg,
duration: 2000
});
}
// Use the getShared API to obtain the LocalStorage instance shared by stage.
@ -38,11 +45,12 @@ struct Index {
type: XComponentType.SURFACE,
libraryname: 'servoshell',
}
private context = getContext(this) as common.UIAbilityContext;
@LocalStorageProp('InitialURI') InitialURI: string = "unused"
@LocalStorageProp('CommandlineArgs') CommandlineArgs: string = ""
@State urlToLoad: string = this.InitialURI
@State tablist: Array<number> = [];
@State currentIndex: number = 0;
// Called when the user swipes from the right or left edge to the middle
// Default behavior is bringing the app to the background.
@ -57,52 +65,85 @@ struct Index {
// Flex.
Flex({ direction: FlexDirection.Column}) {
Row() {
Button('⇦').backgroundColor(Color.White)
Button('+')
.backgroundColor(Color.White)
.fontColor(Color.Black)
.fontWeight(FontWeight.Bolder)
.fontSize(22)
.width('12%')
.onClick((event) => {
if (this.tablist.length==0) {
this.tablist.push(2);
} else {
this.tablist.push(this.tablist[this.tablist.length-1]+1);
}
// yes this is correct as we always have one tab extra
// The tab extra is seperate for the initialization and will always exist.
// It is not in the tablist.
this.currentIndex = this.tablist.length;
})
Button('⇦')
.backgroundColor(Color.White)
.fontColor(Color.Black)
.fontWeight(FontWeight.Bolder)
.width('12%')
.fontSize(12)
.onClick(()=>{
.onClick(() => {
this.onBackPress()
})
Button('⇨').backgroundColor(Color.White)
Button('⇨')
.backgroundColor(Color.White)
.fontColor(Color.Black)
.fontWeight(FontWeight.Bolder)
.fontSize(12)
.width('12%')
.onClick(()=> {
.onClick(() => {
this.xComponentContext?.goForward()
})
TextInput({placeholder:'URL',text: $$this.urlToLoad})
TextInput({ placeholder: 'URL', text: $$this.urlToLoad })
.type(InputType.Normal)
.width('76%')
.onChange((value) => {
this.urlToLoad = value
})
.onSubmit((EnterKeyType)=>{
.onSubmit((EnterKeyType) => {
this.xComponentContext?.loadURL(this.urlToLoad)
console.info('Load URL: ', this.urlToLoad)
})
}
XComponent(this.xComponentAttrs)
.focusable(true)
.onLoad((xComponentContext) => {
this.xComponentContext = xComponentContext as ServoXComponentInterface;
let resource_dir: string = this.context.resourceDir;
console.debug("resourceDir: ", resource_dir);
let init_options: InitOpts = {
url: this.urlToLoad,
resourceDir: resource_dir,
commandlineArgs: this.CommandlineArgs
}
this.xComponentContext.initServo(init_options)
this.xComponentContext.registerURLcallback((new_url) => {
console.info('New URL from native: ', new_url)
this.urlToLoad = new_url
})
this.xComponentContext.registerTerminateCallback(() => { this.context?.terminateSelf(); })
this.xComponentContext.registerPromptToastCallback(prompt_toast)
Tabs({ barPosition: BarPosition.Start, index: this.currentIndex}) {
TabContent() {
XComponent(this.xComponentAttrs)
.focusable(true)
.onLoad((xComponentContext) => {
this.xComponentContext = xComponentContext as ServoXComponentInterface;
let resource_dir: string = this.context.resourceDir;
let cache_dir: string = this.context.cacheDir;
console.debug("resourceDir: ", resource_dir);
console.debug("cacheDir: ", cache_dir);
let init_options: InitOpts = {
url: this.urlToLoad,
resourceDir: resource_dir,
commandlineArgs: this.CommandlineArgs
}
this.xComponentContext.initServo(init_options)
this.xComponentContext.registerURLcallback((new_url) => {
console.info('New URL from native: ', new_url)
this.urlToLoad = new_url
})
this.xComponentContext.registerPromptToastCallback(prompt_toast)
})
}.tabBar('1')
ForEach(this.tablist, (item: number) => {
TabContent() {
XComponent(this.xComponentAttrs)
.focusable(true)
}.tabBar(String(item))
})
}.onChange((index: number) => {
this.xComponentContext?.focusWebview(index);
})
}
.width('100%')
}
@ -112,4 +153,4 @@ interface XComponentAttrs {
id: string;
type: number;
libraryname: string;
}
}