Composer auto-grow (1→5 lines) + in-field attach; settings screen + persisted prefs

- Composer input starts at one line and auto-grows up to 5 lines (then scrolls),
  measured via onTextLayout; attach (paperclip) moved inside the field, right of
  the text, per the Telegram reference.

- New SettingsScreen (drawer/rail entry) for Threads + Tool detail; both now
  persist via SecureStore (Android prefs / desktop JSON).

- Add AGENTS.md; rename reference screenshot to telegram_screenshot_reference.jpg.
This commit is contained in:
ARIA committed 2026-08-20 13:12:24 +02:00
1 parent bf6bf7e8bd
commit e678caafdc
8 files changed
+306 -58

No files matched your search

@@ -80,8 +80,9 @@ class IrisController(
private val _typing = MutableStateFlow(false)
val typing: StateFlow<Boolean> = _typing.asStateFlow()
/** Tool-card verbosity (M2). NOTHING suppresses tool cards entirely. */
private val _toolDetail = MutableStateFlow(ToolDetail.TRUNCATED)
/** Tool-card verbosity (M2). NOTHING suppresses tool cards entirely.
* Persisted (Settings → "Tool detail"). */
private val _toolDetail = MutableStateFlow(ToolDetail.fromName(store.toolDetail))
val toolDetail: StateFlow<ToolDetail> = _toolDetail.asStateFlow()
fun cycleToolDetail() {
@@ -90,6 +91,13 @@ class IrisController(
ToolDetail.TRUNCATED -> ToolDetail.NOTHING
ToolDetail.NOTHING -> ToolDetail.EVERYTHING
}
store.toolDetail = _toolDetail.value.name.lowercase()
}
fun setToolDetail(detail: ToolDetail) {
if (detail == _toolDetail.value) return
_toolDetail.value = detail
store.toolDetail = detail.name.lowercase()
}
/** Home channel id (from hello.ack; default until then). */
@@ -101,11 +109,13 @@ class IrisController(
val gatewayStatus: StateFlow<String?> = _gatewayStatus.asStateFlow()
// ── M3: threads toggle (per-app for now; per-channel lands later) ─────
private val _threadsEnabled = MutableStateFlow(false)
// Persisted (Settings → "Threads").
private val _threadsEnabled = MutableStateFlow(store.threadsEnabled)
val threadsEnabled: StateFlow<Boolean> = _threadsEnabled.asStateFlow()
fun toggleThreads() {
_threadsEnabled.value = !_threadsEnabled.value
store.threadsEnabled = _threadsEnabled.value
}
// ── M3: search state ──────────────────────────────────────────────────
@@ -487,4 +497,11 @@ enum class ToolDetail {
EVERYTHING, // name + full args (collapsible) + output preview
TRUNCATED, // one-liner "emoji name: preview", collapsible (default)
NOTHING, // suppress tool cards entirely
;
companion object {
/** Parse a persisted value; unknown/blank falls back to the default. */
fun fromName(name: String): ToolDetail =
entries.firstOrNull { it.name.equals(name, ignoreCase = true) } ?: TRUNCATED
}
}