blob: 8a9dfe03afd620803c387299e2204afafbe5af7d [file] [log] [blame]
// Copyright (C) 2024 The Android Open Source Project
//
// 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.
import {OmniboxManager, PromptOption} from '../public/omnibox';
import {raf} from './raf_scheduler';
export enum OmniboxMode {
Search,
Query,
Command,
Prompt,
}
interface Prompt {
text: string;
options?: PromptOption[];
resolve(result: string | undefined): void;
}
const defaultMode = OmniboxMode.Search;
export class OmniboxManagerImpl implements OmniboxManager {
private _mode = defaultMode;
private _focusOmniboxNextRender = false;
private _pendingCursorPlacement?: number;
private _pendingPrompt?: Prompt;
private _omniboxSelectionIndex = 0;
private _forceShortTextSearch = false;
private _textForMode = new Map<OmniboxMode, string>();
private _statusMessageContainer: {msg?: string} = {};
get mode(): OmniboxMode {
return this._mode;
}
get pendingPrompt(): Prompt | undefined {
return this._pendingPrompt;
}
get text(): string {
return this._textForMode.get(this._mode) ?? '';
}
get selectionIndex(): number {
return this._omniboxSelectionIndex;
}
get focusOmniboxNextRender(): boolean {
return this._focusOmniboxNextRender;
}
get pendingCursorPlacement(): number | undefined {
return this._pendingCursorPlacement;
}
get forceShortTextSearch() {
return this._forceShortTextSearch;
}
setText(value: string): void {
this._textForMode.set(this._mode, value);
}
setSelectionIndex(index: number): void {
this._omniboxSelectionIndex = index;
}
focus(cursorPlacement?: number): void {
this._focusOmniboxNextRender = true;
this._pendingCursorPlacement = cursorPlacement;
raf.scheduleFullRedraw();
}
clearFocusFlag(): void {
this._focusOmniboxNextRender = false;
this._pendingCursorPlacement = undefined;
}
setMode(mode: OmniboxMode, focus = true): void {
this._mode = mode;
this._focusOmniboxNextRender = focus;
this._omniboxSelectionIndex = 0;
this.rejectPendingPrompt();
raf.scheduleFullRedraw();
}
showStatusMessage(msg: string, durationMs = 2000) {
const statusMessageContainer: {msg?: string} = {msg};
if (durationMs > 0) {
setTimeout(() => {
statusMessageContainer.msg = undefined;
raf.scheduleFullRedraw();
}, durationMs);
}
this._statusMessageContainer = statusMessageContainer;
raf.scheduleFullRedraw();
}
get statusMessage(): string | undefined {
return this._statusMessageContainer.msg;
}
// Start a prompt. If options are supplied, the user must pick one from the
// list, otherwise the input is free-form text.
prompt(text: string, options?: PromptOption[]): Promise<string | undefined> {
this._mode = OmniboxMode.Prompt;
this._omniboxSelectionIndex = 0;
this.rejectPendingPrompt();
const promise = new Promise<string | undefined>((resolve) => {
this._pendingPrompt = {
text,
options,
resolve,
};
});
this._focusOmniboxNextRender = true;
raf.scheduleFullRedraw();
return promise;
}
// Resolve the pending prompt with a value to return to the prompter.
resolvePrompt(value: string): void {
if (this._pendingPrompt) {
this._pendingPrompt.resolve(value);
this._pendingPrompt = undefined;
}
this.setMode(OmniboxMode.Search);
}
// Reject the prompt outright. Doing this will force the owner of the prompt
// promise to catch, so only do this when things go seriously wrong.
// Use |resolvePrompt(null)| to indicate cancellation.
rejectPrompt(): void {
this.rejectPendingPrompt();
this.setMode(OmniboxMode.Search);
}
reset(focus = true): void {
this.setMode(defaultMode, focus);
this._omniboxSelectionIndex = 0;
this._statusMessageContainer = {};
raf.scheduleFullRedraw();
}
private rejectPendingPrompt() {
if (this._pendingPrompt) {
this._pendingPrompt.resolve(undefined);
this._pendingPrompt = undefined;
}
}
}