-
Notifications
You must be signed in to change notification settings - Fork 896
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Autofocuses input box on Android Leo chat window on a fresh chat #25512
base: master
Are you sure you want to change the base?
Conversation
9151f4f
to
00844ae
Compare
A Storybook has been deployed to preview UI for the latest push |
A Storybook has been deployed to preview UI for the latest push |
A Storybook has been deployed to preview UI for the latest push |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly looks great with a few comments 😄
@@ -76,10 +78,21 @@ function InputBox(props: InputBoxProps) { | |||
} | |||
} | |||
|
|||
const querySubmitted = React.useRef(false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: not strictly required but I'd prefer this to be defined before its used (i.e. before handleSubmit
)
components/ai_chat/resources/page/components/input_box/index.tsx
Outdated
Show resolved
Hide resolved
if (props.context.isMobile && props.context.hasAcceptedAgreement && | ||
!props.context.hasInitialHistory && !querySubmitted.current) { | ||
node.focus() | ||
getPageHandlerInstance().pageHandler.handleShowSoftKeyboard() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should go through the context
so we can bind the input_box
to another mojom interface (which I think we do for the AI Rewriter stuff, which currently isn't active)
@@ -336,6 +336,8 @@ function DataContextProvider(props: DataContextProviderProps) { | |||
} | |||
|
|||
const isMobile = React.useMemo(() => loadTimeData.getBoolean('isMobile'), []) | |||
const hasInitialHistory = React.useMemo(() => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know you're just following what this file does but I don't think there's any point to this being in a useMemo
as:
- It isn't an expensive calculation (so we could just store it in a normal variable)
- It will never change
Personally, I'd probably store the variable outside the component as
const hasInitialHistory = loadTimeData.getBoolean('hasInitialHistory')
function DataContextProvider(...) {
...
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really this shouldn't be part of the context at all as its completely static data, but I guess its fine as part of the interface the input_box
expects.
6932add
to
4756a38
Compare
@fallaciousreasoning the review suggestions are addressed. |
content::WebContents* chat_web_contents = GetChatWebContents(); | ||
size_t visible_conversation_history_size = 0; | ||
if (chat_web_contents) { | ||
ai_chat::AIChatTabHelper* active_chat_tab_helper = | ||
ai_chat::AIChatTabHelper::FromWebContents(chat_web_contents); | ||
visible_conversation_history_size = | ||
active_chat_tab_helper->GetVisibleConversationHistory().size(); | ||
} | ||
untrusted_source->AddBoolean("hasInitialHistory", | ||
visible_conversation_history_size != 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this needs to be provided by the C++. The context can just check if the first call to get conversation history has any data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@petemill what particular call do you mean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@fallaciousreasoning the getConversationHistory
returns 0 always even if we have history.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Surely there's some way that we load the active conversation history because we display it, right?
node.focus() | ||
} | ||
if (props.context.isMobile && props.context.hasAcceptedAgreement && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm thinking this should be done in a higher level because input is shared with ai rewriter dialog - it doesn't need to be in a conversation with history and doesn't need to have conversation awareness. We can also remove the props.context.isMobile
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can move the check on the higher level but node.focus
would be called here depending of true
false
the higher check function return. The rewriter could just have have a stub with false. Does the rewriter need to be aware of hasAcceptedAgreement
as it was there before?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I moved it to the higher level
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is focus not enugh to show the virtual keyboard? If this is in a regular Tab instead of a custom popup, would we still require a custom HandleShowSoftKeyboard
function? I'm asking because wondering if it's worth the effort due to us soon removing the custom popup in favor of a Tab.
I've been fighting with it and it doesn't pop up when I programmatically call focus. The conclusion from other users who tried that was something like that |
d81551d
to
42164ae
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm % nits
| 'shouldDisableUserInput' | ||
| 'hasAcceptedAgreement'> | ||
|
||
interface InputBoxProps { | ||
context: Props | ||
onFocusInputMobile?: () => unknown | ||
maybeShowSoftKeyboard?: (querySubmitted: boolean) => unknown |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hey sorry, I know you're just cargo culting here but I think these methods should return void
rather than unknown.
Even if we do return something from these functions its fine, it just means the InputBox
doesn't do anything with the return type.
For example, the below is fine:
let foo: ((n: number) => void) = n => n * n
@@ -63,6 +63,7 @@ export interface AIChatContext extends CharCountContext { | |||
resetSelectedActionType: () => void | |||
handleActionTypeClick: (actionType: mojom.ActionType) => void | |||
setIsToolsMenuOpen: (isOpen: boolean) => void | |||
handleShowSoftKeyboard?: () => unknown |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here:
handleShowSoftKeyboard?: () => unknown | |
handleShowSoftKeyboard?: () => void |
} | ||
|
||
function InputBox(props: InputBoxProps) { | ||
const onInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => { | ||
props.context.setInputText(e.target.value) | ||
} | ||
|
||
const querySubmitted = React.useRef(false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optional: I'm pretty sure we could use useState
here instead of useRef (though not 100%).
@@ -78,21 +80,16 @@ function InputBox(props: InputBoxProps) { | |||
} | |||
} | |||
|
|||
const querySubmitted = React.useRef(false) | |||
|
|||
const maybeAutofocus = (node: HTMLTextAreaElement | null) => { | |||
if (!node) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a bit curious about how often this gets called - is it every render, or is it only when the ref (node
) is changed?
content::WebContents* chat_web_contents = GetChatWebContents(); | ||
size_t visible_conversation_history_size = 0; | ||
if (chat_web_contents) { | ||
ai_chat::AIChatTabHelper* active_chat_tab_helper = | ||
ai_chat::AIChatTabHelper::FromWebContents(chat_web_contents); | ||
visible_conversation_history_size = | ||
active_chat_tab_helper->GetVisibleConversationHistory().size(); | ||
} | ||
untrusted_source->AddBoolean("hasInitialHistory", | ||
visible_conversation_history_size != 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
42164ae
to
07cab19
Compare
b954367
to
39a8cdd
Compare
A Storybook has been deployed to preview UI for the latest push |
39a8cdd
to
0cdd853
Compare
0cdd853
to
36292c7
Compare
A Storybook has been deployed to preview UI for the latest push |
Resolves brave/brave-browser#40968
Submitter Checklist:
QA/Yes
orQA/No
;release-notes/include
orrelease-notes/exclude
;OS/...
) to the associated issuenpm run test -- brave_browser_tests
,npm run test -- brave_unit_tests
wikinpm run presubmit
wiki,npm run gn_check
,npm run tslint
git rebase master
(if needed)Reviewer Checklist:
gn
After-merge Checklist:
changes has landed on
Test Plan:
Screen_recording_20240910_154410.webm
the test plan is specified in the issue