-
Notifications
You must be signed in to change notification settings - Fork 0
π¨ Palette: Enable Send IME action in ChatScreen text input #23
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
base: main
Are you sure you want to change the base?
Changes from all commits
ee2fc1e
33206e5
bc42722
e9488e3
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 |
|---|---|---|
|
|
@@ -7,6 +7,8 @@ import androidx.compose.foundation.layout.fillMaxWidth | |
| import androidx.compose.foundation.layout.padding | ||
| import androidx.compose.foundation.lazy.LazyColumn | ||
| import androidx.compose.foundation.lazy.items | ||
| import androidx.compose.foundation.text.KeyboardActions | ||
| import androidx.compose.foundation.text.KeyboardOptions | ||
| import androidx.compose.material3.Button | ||
| import androidx.compose.material3.ExperimentalMaterial3Api | ||
| import androidx.compose.material3.OutlinedTextField | ||
|
|
@@ -21,6 +23,7 @@ import androidx.compose.runtime.remember | |
| import androidx.compose.runtime.setValue | ||
| import androidx.compose.ui.Alignment | ||
| import androidx.compose.ui.Modifier | ||
| import androidx.compose.ui.text.input.ImeAction | ||
| import androidx.compose.ui.unit.dp | ||
| import com.sayanthrock.freeairock.ui.AppViewModel | ||
|
|
||
|
|
@@ -60,7 +63,17 @@ fun ChatScreen(viewModel: AppViewModel, modifier: Modifier = Modifier) { | |
| value = inputText, | ||
| onValueChange = { inputText = it }, | ||
| modifier = Modifier.weight(1f), | ||
| placeholder = { Text("Message AI...") } | ||
| placeholder = { Text("Message AI...") }, | ||
| singleLine = true, | ||
| keyboardOptions = KeyboardOptions(imeAction = ImeAction.Send), | ||
| keyboardActions = KeyboardActions( | ||
| onSend = { | ||
| if (inputText.isNotBlank()) { | ||
| viewModel.sendMessage(inputText) | ||
| inputText = "" | ||
| } | ||
| } | ||
| ) | ||
|
Comment on lines
+68
to
+76
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. π― Functional Correctness | π‘ Minor | β‘ Quick win π§© Analysis chainπ Script executed: #!/bin/bash
set -eu
file='app/src/main/java/com/sayanthrock/freeairock/ui/chat/ChatScreen.kt'
printf '%s\n' '--- target file ---'
sed -n '1,130p' "$file"
printf '%s\n' '--- related keyboard action usage ---'
rg -n -C 3 'KeyboardActions|KeyboardOptions|onSend|ImeAction\.(Send|Done|Go|Next)' app/src/main
printf '%s\n' '--- Compose dependency declarations ---'
rg -n -C 2 'compose|androidx.compose|foundation' --glob 'build.gradle*' --glob 'libs.versions.toml' --glob 'gradle.properties' .Repository: SayanthRock/FREE-AI-ROCK- Length of output: 11463 π Script executed: #!/bin/bash
set -eu
python3 - <<'PY'
from urllib.request import Request, urlopen
from urllib.error import HTTPError
urls = {
"KeyboardActions.kt":
"https://raw.githubusercontent.com/androidx/androidx/androidx-compose-foundation-1.6.8/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyboardActions.kt",
"BasicTextField.kt":
"https://raw.githubusercontent.com/androidx/androidx/androidx-compose-foundation-1.6.8/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/BasicTextField.kt",
}
for name, url in urls.items():
print(f"--- {name} ---")
try:
text = urlopen(Request(url, headers={"User-Agent": "review-read-only-check"}), timeout=10).read().decode()
except HTTPError as exc:
print(f"HTTP {exc.code}: {url}")
continue
lines = text.splitlines()
needles = ("class KeyboardActions", "fun KeyboardActions", "onAny", "onSend",
"ImeAction", "keyboardActionHandler", "performAction")
for i, line in enumerate(lines):
if any(needle in line for needle in needles):
lo, hi = max(0, i - 3), min(len(lines), i + 8)
print(f"[{lo + 1}-{hi}]")
print("\n".join(f"{j + 1}: {lines[j]}" for j in range(lo, hi)))
PY
python3 - <<'PY'
# Read-only behavioral probe for the documented dispatch rule:
# an exact action selects its matching callback; an unsupported action
# selects onAny, not onSend.
actions = ("Default", "None", "Go", "Search", "Send", "Next", "Done", "Previous")
callbacks = {name: name for name in ("onDone", "onGo", "onNext", "onPrevious", "onSearch", "onSend")}
def dispatch(action, on_any=None):
exact = "on" + action
return callbacks.get(exact, on_any)
for action in actions:
print(f"{action}: {dispatch(action, on_any='onAny')}")
assert dispatch("Send", on_any="onAny") == "onSend"
assert dispatch("Done", on_any="onAny") == "onAny"
assert dispatch("Done") is None
print("dispatch assertions: passed")
PYRepository: SayanthRock/FREE-AI-ROCK- Length of output: 2477 π Script executed: #!/bin/bash
set -eu
python3 - <<'PY'
from urllib.request import Request, urlopen
from urllib.error import HTTPError
urls = {
"KeyboardActions.kt":
"https://raw.githubusercontent.com/androidx/androidx/androidx-compose-foundation-1.6.8/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyboardActions.kt",
"BasicTextField.kt":
"https://raw.githubusercontent.com/androidx/androidx/androidx-compose-foundation-1.6.8/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/BasicTextField.kt",
}
for name, url in urls.items():
print(f"--- {name} ---")
try:
text = urlopen(Request(url, headers={"User-Agent": "review-read-only-check"}), timeout=10).read().decode()
except HTTPError as exc:
print(f"HTTP {exc.code}: {url}")
continue
lines = text.splitlines()
needles = ("class KeyboardActions", "fun KeyboardActions", "onAny", "onSend",
"ImeAction", "keyboardActionHandler", "performAction")
for i, line in enumerate(lines):
if any(needle in line for needle in needles):
lo, hi = max(0, i - 3), min(len(lines), i + 8)
print(f"[{lo + 1}-{hi}]")
print("\n".join(f"{j + 1}: {lines[j]}" for j in range(lo, hi)))
PY
python3 - <<'PY'
actions = ("Default", "None", "Go", "Search", "Send", "Next", "Done", "Previous")
callbacks = {name: name for name in ("onDone", "onGo", "onNext", "onPrevious", "onSearch", "onSend")}
def dispatch(action, on_any=None):
exact = "on" + action
return callbacks.get(exact, on_any)
for action in actions:
print(f"{action}: {dispatch(action, on_any='onAny')}")
assert dispatch("Send", on_any="onAny") == "onSend"
assert dispatch("Done", on_any="onAny") == "onAny"
assert dispatch("Done") is None
print("dispatch assertions: passed")
PYRepository: SayanthRock/FREE-AI-ROCK- Length of output: 2477 π Script executed: #!/bin/bash
set -u
base='https://raw.githubusercontent.com/androidx/androidx/androidx-compose-foundation-1.6.8/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text'
for name in KeyboardActions.kt BasicTextField.kt; do
echo "--- $name ---"
curl -k -L --fail --silent --show-error "$base/$name" |
nl -ba |
grep -E -C 6 'class KeyboardActions|onAny|onSend|ImeAction|KeyboardActionRunner|keyboardActionHandler|performAction'
done
echo '--- Android API documentation ---'
curl -k -L --fail --silent --show-error \
'https://developer.android.com/reference/kotlin/androidx/compose/foundation/text/KeyboardActions' |
grep -oE '.{0,180}(onAny|onSend|different action|imeAction).{0,300}' |
head -n 20Repository: SayanthRock/FREE-AI-ROCK- Length of output: 4709 π Web query:
π‘ Result: In Jetpack Compose, including version 1.6.8, KeyboardActions is a class used to define custom behaviors when a user triggers an IME (Input Method Editor) action on the software keyboard [1][2]. The distinction between onAny and specific actions like onSend is as follows: onAny is a factory function provided for convenience [2][3]. It creates a KeyboardActions instance where the same lambda function is executed regardless of which specific IME action (e.g., Done, Go, Next, Previous, Search, or Send) is triggered by the user [2][4]. Internally, it maps the provided lambda to all available IME actions [4]. onSend is a specific property within the KeyboardActions class [1]. It allows you to define a callback that triggers exclusively when the user performs the Send IME action [1]. In summary: - Use onAny if you want a single, unified callback to handle every type of IME action [2][5]. - Use specific properties like onSend if you need to perform different logic depending on the specific action triggered by the user [1][5]. If a property (such as onSend) is left as null, the system will attempt to execute its default implementation if one exists [1]. For example, the default behavior for onNext and onPrevious is to manage focus traversal [1]. Citations:
π Script executed: #!/bin/bash
set -eu
python3 - <<'PY'
import html
import re
import subprocess
urls = [
"https://developer.android.com/reference/kotlin/androidx/compose/foundation/text/KeyboardActions",
"https://developer.android.com/reference/kotlin/androidx/compose/foundation/text/package-summary",
]
for url in urls:
print(f"--- {url} ---")
raw = subprocess.check_output(
["curl", "-k", "-L", "--fail", "--silent", "--show-error", url],
text=True,
)
text = html.unescape(re.sub(r"<[^>]+>", " ", raw))
text = re.sub(r"\s+", " ", text)
terms = ("onAny", "onSend", "different action", "imeAction", "KeyboardActions(")
for term in terms:
positions = [m.start() for m in re.finditer(re.escape(term), text, re.I)]
for pos in positions[:3]:
print(text[max(0, pos - 220):pos + 420])
PY
python3 - <<'PY'
# Read-only API-shape check based on the documented Compose distinction.
# A specific callback is selected only for its matching action; onAny is
# the unified fallback when every action must submit.
specific = {"Done", "Go", "Next", "Previous", "Search", "Send"}
def callback(action, handlers, any_handler=None):
if action in specific and action in handlers:
return handlers[action]
return any_handler
submit = object()
assert callback("Send", {"Send": submit}, any_handler=None) is submit
assert callback("Done", {"Send": submit}, any_handler=None) is None
assert callback("Done", {}, any_handler=submit) is submit
assert callback("Send", {}, any_handler=submit) is submit
print("specific-action and onAny fallback assertions: passed")
PYRepository: SayanthRock/FREE-AI-ROCK- Length of output: 7476 π Script executed: #!/bin/bash
set -eu
python3 - <<'PY'
import html
import re
import subprocess
urls = [
"https://developer.android.com/reference/kotlin/androidx/compose/foundation/text/KeyboardActions",
"https://developer.android.com/reference/kotlin/androidx/compose/foundation/text/package-summary",
]
for url in urls:
print(f"--- {url} ---")
raw = subprocess.check_output(
["curl", "-k", "-L", "--fail", "--silent", "--show-error", url],
text=True,
)
text = html.unescape(re.sub(r"<[^>]+>", " ", raw))
text = re.sub(r"\s+", " ", text)
terms = ("onAny", "onSend", "different action", "imeAction", "KeyboardActions(")
for term in terms:
positions = [m.start() for m in re.finditer(re.escape(term), text, re.I)]
for pos in positions[:3]:
print(text[max(0, pos - 220):pos + 420])
PY
python3 - <<'PY'
specific = {"Done", "Go", "Next", "Previous", "Search", "Send"}
def callback(action, handlers, any_handler=None):
if action in specific and action in handlers:
return handlers[action]
return any_handler
submit = object()
assert callback("Send", {"Send": submit}, any_handler=None) is submit
assert callback("Done", {"Send": submit}, any_handler=None) is None
assert callback("Done", {}, any_handler=submit) is submit
assert callback("Send", {}, any_handler=submit) is submit
print("specific-action and onAny fallback assertions: passed")
PYRepository: SayanthRock/FREE-AI-ROCK- Length of output: 7476 Handle fallback IME actions.
π€ Prompt for AI Agents |
||
| ) | ||
| Button( | ||
| onClick = { | ||
|
|
||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
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.
Suggestion: Setting
singleLinetotruechanges the existing text-input contract by preventing users from entering line breaks in chat messages. Since the full field value is passed directly tosendMessage, multiline prompts that were previously supported are now truncated or submitted through the IME action instead of retaining their newline content. Preserve multiline input or explicitly handle newline insertion if multiline prompts are supported. [api mismatch]Severity Level: Majorβ οΈ
Prompt for AI Agent π€