Merge branch 'main' of git.arirex.me:iris/ai-app

This commit is contained in:
iris committed 2026-08-30 02:52:51 -04:00
commit 7190eac6f3
6 files changed
+296 -11

No files matched your search

@@ -1686,6 +1686,16 @@ private fun QuestionRow(
}
}
/**
* How long after a menu closes a press on its own button still counts as the press that closed it.
*
* Sized to one tap, because one tap is all it has to span -- [PickerButton] explains the pair of
* events it separates. Deliberately not the platform's long-press timeout, which is the longest a
* tap can legally be: half a second of ignoring the button would start swallowing a deliberate
* reopen, and a press held that long to close a menu is not worth protecting at that price.
*/
private const val ONE_TAP_MS = 250L
/** The modes the CLI accepts, in the order they give up asking. */
private val PERMISSION_MODES = listOf("manual", "acceptEdits", "auto", "bypassPermissions", "plan")
@@ -1698,8 +1708,21 @@ private val PERMISSION_MODES = listOf("manual", "acceptEdits", "auto", "bypassPe
@Composable
private fun PickerButton(current: String, options: List<String>, onPick: (String) -> Unit) {
var open by remember { mutableStateOf(false) }
// When an outside touch last closed the menu.
//
// Pressing this button while its own menu is open is such a touch. The menu is deliberately
// not focusable (see below), which means the press that dismisses it is also delivered to the
// window underneath -- and what it lands on there is this button. The dismissal arrives with
// the press and the click with the release, measured 3ms apart on the emulator, so a button
// that simply opened on every click would reopen what the same finger had just closed, and
// the menu could only be put away by tapping somewhere else. So the moment is remembered, and
// a click that follows it within one tap is read as the second half of that tap rather than
// as a new one.
var closedAt by remember { mutableLongStateOf(0L) }
Box {
TextButton(onClick = { open = true }) {
TextButton(
onClick = { if (SystemClock.uptimeMillis() - closedAt > ONE_TAP_MS) open = true }
) {
// One line, truncated rather than wrapped: this sits in a row
// whose height is the buttons beside it, and a second line
// would move them.
@@ -1731,7 +1754,10 @@ private fun PickerButton(current: String, options: List<String>, onPick: (String
// this menu takes no parameter for.
DropdownMenu(
expanded = open,
onDismissRequest = { open = false },
onDismissRequest = {
open = false
closedAt = SystemClock.uptimeMillis()
},
properties = PopupProperties(focusable = false, clippingEnabled = false),
) {
options.forEach { option ->