-
Notifications
You must be signed in to change notification settings - Fork 0
π¨ Palette: Keyboard Accessibility and Smart Filename Extraction #10
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| # Palette's Journal π¨ | ||
|
|
||
| A record of critical UX and accessibility learnings. | ||
|
|
||
| ## 2025-02-15 - Interactive Soft-Keyboard Forms in Jetpack Compose | ||
| **Learning:** Text input forms lacking appropriate `ImeAction` and `KeyboardActions` force the user to manually dismiss the virtual keyboard and tap submission buttons, creating friction, especially for users relying on screen readers or single-hand navigation. By configuring standard text field focus transitions and executing the button's action directly from the soft keyboard's Search/Done key, form ergonomics improve dramatically. | ||
| **Action:** Always configure `keyboardOptions = KeyboardOptions(imeAction = ...)` and `keyboardActions = KeyboardActions(on... = { ... })` for input forms with multiple fields or quick actions in Jetpack Compose. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,8 +26,11 @@ import androidx.compose.runtime.mutableStateOf | |
| import androidx.compose.runtime.remember | ||
| import androidx.compose.runtime.setValue | ||
| import androidx.compose.ui.Modifier | ||
| import androidx.compose.foundation.text.KeyboardActions | ||
| import androidx.compose.foundation.text.KeyboardOptions | ||
| import androidx.compose.ui.platform.LocalClipboardManager | ||
| import androidx.compose.ui.text.AnnotatedString | ||
| import androidx.compose.ui.text.input.ImeAction | ||
| import androidx.compose.ui.text.input.PasswordVisualTransformation | ||
| import androidx.compose.ui.unit.dp | ||
| import androidx.lifecycle.ViewModelProvider | ||
|
|
@@ -203,7 +206,16 @@ private fun CodeAnalyzerScreen( | |
| label = { Text("GitHub token") }, | ||
| visualTransformation = PasswordVisualTransformation(), | ||
| modifier = Modifier.fillMaxWidth(), | ||
| singleLine = true | ||
| singleLine = true, | ||
| keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), | ||
| keyboardActions = KeyboardActions( | ||
| onDone = { | ||
| if (githubToken.isNotBlank()) { | ||
| onSave(githubToken) | ||
| savedMessage = "Saved securely on this device" | ||
| } | ||
| } | ||
| ) | ||
| ) | ||
|
|
||
|
|
||
|
|
@@ -243,17 +255,36 @@ private fun CodeAnalyzerScreen( | |
| onValueChange = { fileName = it }, | ||
| label = { Text("File name") }, | ||
| modifier = Modifier.fillMaxWidth(), | ||
| singleLine = true | ||
| singleLine = true, | ||
| keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next) | ||
| ) | ||
|
|
||
| Spacer(modifier = Modifier.height(12.dp)) | ||
|
|
||
| OutlinedTextField( | ||
| value = fileUrl, | ||
| onValueChange = { fileUrl = it }, | ||
| onValueChange = { url -> | ||
| fileUrl = url | ||
| if (url.isNotBlank()) { | ||
| val cleanUrl = url.substringBefore("?").substringBefore("#") | ||
| val parts = cleanUrl.split('/') | ||
| val lastPart = parts.lastOrNull() | ||
| if (!lastPart.isNullOrBlank() && lastPart.contains('.')) { | ||
| fileName = lastPart | ||
| } | ||
| } | ||
| }, | ||
|
Comment on lines
+266
to
+276
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: Every nonblank URL edit overwrites Severity Level: Major
|
||
| label = { Text("GitHub raw/blob file URL") }, | ||
| modifier = Modifier.fillMaxWidth(), | ||
| singleLine = true | ||
| singleLine = true, | ||
| keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search), | ||
| keyboardActions = KeyboardActions( | ||
| onSearch = { | ||
| if (uiState !is CodeAnalysisState.Loading && fileUrl.isNotBlank()) { | ||
| onAnalyze(fileName, fileUrl) | ||
| } | ||
| } | ||
| ) | ||
| ) | ||
|
|
||
| Spacer(modifier = Modifier.height(16.dp)) | ||
|
|
||
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.
π― Functional Correctness | π‘ Minor | β‘ Quick win
π§© Analysis chain
π Script executed:
Repository: SayanthRock/FREE-AI-ROCK-
Length of output: 20047
π Script executed:
Repository: SayanthRock/FREE-AI-ROCK-
Length of output: 7683
π Web query:
Android Jetpack Compose KeyboardActions defaultKeyboardAction ImeAction Done source documentationπ‘ Result:
In Jetpack Compose, defaultKeyboardAction is a function provided within the KeyboardActionScope interface [1]. It is designed to trigger the system's default behavior associated with a specific ImeAction [1]. When you invoke defaultKeyboardAction(ImeAction.Done), it executes the standard implementation for the "Done" action, which is to close the software keyboard [2]. Key technical details include: - KeyboardActionScope: This interface provides the context for executing custom keyboard actions [1]. Within its scope, you can call defaultKeyboardAction(imeAction) to trigger the default behavior for any given ImeAction [1]. - ImeAction.Done: This constant represents the "Done" action, signaling that the user has finished providing input to a field or a group of fields [3]. When used with defaultKeyboardAction, it specifically invokes the platform-level implementation that hides the software keyboard [2]. - Default Behavior: If you provide a custom lambda for an action (e.g., onDone in KeyboardActions), the default behavior is overridden [4]. To execute the default behavior while still performing custom logic, you can manually call defaultKeyboardAction(ImeAction.Done) inside your custom callback [1]. This mechanism ensures that developers can maintain standard platform expectationsβsuch as keyboard dismissal upon completionβwhile still having the flexibility to implement custom application-specific logic [4][5].
Citations:
Restore the default Done action after saving the token.
KeyboardActions.onDoneoverrides the default IME action. The custom callback saves the token but does not hide the keyboard, so the confirmation text can remain covered by the software keyboard. RundefaultKeyboardAction(ImeAction.Done)after saving to keep the normal Done behavior.Proposed fix
if (githubToken.isNotBlank()) { onSave(githubToken) savedMessage = "Saved securely on this device" + defaultKeyboardAction(ImeAction.Done) }π Committable suggestion
π€ Prompt for AI Agents