Skip to content

Commit 5a9e540

Browse files
committed
feat(android): add in-chat model picker with favorites and recents
1 parent 3442a8e commit 5a9e540

13 files changed

Lines changed: 668 additions & 39 deletions

File tree

apps/.i18n/native-source.json

Lines changed: 56 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -147,15 +147,15 @@
147147
},
148148
{
149149
"kind": "ui-state-text",
150-
"line": 202,
150+
"line": 204,
151151
"path": "apps/android/app/src/main/java/ai/openclaw/app/MainViewModel.kt",
152152
"source": "Mic off",
153153
"surface": "android",
154154
"id": "native.android.567482ea1118eb13"
155155
},
156156
{
157157
"kind": "ui-state-text",
158-
"line": 212,
158+
"line": 214,
159159
"path": "apps/android/app/src/main/java/ai/openclaw/app/MainViewModel.kt",
160160
"source": "Off",
161161
"surface": "android",
@@ -203,23 +203,23 @@
203203
},
204204
{
205205
"kind": "conditional-branch",
206-
"line": 2465,
206+
"line": 2467,
207207
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
208208
"source": "Failed: this host requires wss:// or Tailscale Serve. No TLS endpoint detected.",
209209
"surface": "android",
210210
"id": "native.android.81009c40eed2216d"
211211
},
212212
{
213213
"kind": "conditional-branch",
214-
"line": 2467,
214+
"line": 2469,
215215
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
216216
"source": "Failed: secure endpoint reached, but TLS fingerprint verification timed out. Check Tailscale Serve or gateway TLS and retry.",
217217
"surface": "android",
218218
"id": "native.android.467899bb510b8e34"
219219
},
220220
{
221221
"kind": "conditional-branch",
222-
"line": 2469,
222+
"line": 2471,
223223
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
224224
"source": "Failed: couldn't reach the secure gateway endpoint for this host.",
225225
"surface": "android",
@@ -5867,215 +5867,239 @@
58675867
},
58685868
{
58695869
"kind": "ui-named-argument",
5870-
"line": 236,
5870+
"line": 272,
58715871
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt",
58725872
"source": "Chat needs attention",
58735873
"surface": "android",
58745874
"id": "native.android.22a4efbe2bab8b80"
58755875
},
58765876
{
58775877
"kind": "ui-named-argument",
5878-
"line": 378,
5878+
"line": 430,
58795879
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt",
58805880
"source": "All",
58815881
"surface": "android",
58825882
"id": "native.android.b73c79389a8cff07"
58835883
},
58845884
{
58855885
"kind": "ui-named-argument",
5886-
"line": 436,
5886+
"line": 488,
58875887
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt",
58885888
"source": "OpenClaw",
58895889
"surface": "android",
58905890
"id": "native.android.25d8575c0063aee5"
58915891
},
58925892
{
58935893
"kind": "ui-named-argument",
5894-
"line": 457,
5894+
"line": 509,
58955895
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt",
58965896
"source": "New chat",
58975897
"surface": "android",
58985898
"id": "native.android.4437f3cbdb3c8cbe"
58995899
},
59005900
{
59015901
"kind": "ui-named-argument",
5902-
"line": 462,
5902+
"line": 514,
59035903
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt",
59045904
"source": "More new chat options",
59055905
"surface": "android",
59065906
"id": "native.android.6b0f8ea129bca167"
59075907
},
59085908
{
59095909
"kind": "ui-named-argument",
5910-
"line": 477,
5910+
"line": 529,
59115911
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt",
59125912
"source": "Refresh chat",
59135913
"surface": "android",
59145914
"id": "native.android.0066c3883e9eff15"
59155915
},
59165916
{
59175917
"kind": "ui-named-argument",
5918-
"line": 480,
5918+
"line": 532,
59195919
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt",
59205920
"source": "Chat",
59215921
"surface": "android",
59225922
"id": "native.android.707eccff20a79f65"
59235923
},
59245924
{
59255925
"kind": "ui-named-argument",
5926-
"line": 622,
5926+
"line": 674,
59275927
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt",
59285928
"source": "Loading session",
59295929
"surface": "android",
59305930
"id": "native.android.882cc14a58e7e105"
59315931
},
59325932
{
59335933
"kind": "ui-named-argument",
5934-
"line": 649,
5934+
"line": 701,
59355935
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt",
59365936
"source": "Jump to latest",
59375937
"surface": "android",
59385938
"id": "native.android.2c1106e1687ab258"
59395939
},
59405940
{
59415941
"kind": "conditional-branch",
5942-
"line": 669,
5942+
"line": 721,
59435943
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt",
59445944
"source": "Ready when you are",
59455945
"surface": "android",
59465946
"id": "native.android.9df2c9d68bad169f"
59475947
},
59485948
{
59495949
"kind": "ui-named-argument",
5950-
"line": 700,
5950+
"line": 752,
59515951
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt",
59525952
"source": "Fix connection",
59535953
"surface": "android",
59545954
"id": "native.android.6bbe3c5b5193d985"
59555955
},
59565956
{
59575957
"kind": "ui-named-argument",
5958-
"line": 701,
5958+
"line": 753,
59595959
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt",
59605960
"source": "Copy diagnostics",
59615961
"surface": "android",
59625962
"id": "native.android.579c05816c7dfa79"
59635963
},
59645964
{
59655965
"kind": "ui-named-argument",
5966-
"line": 852,
5966+
"line": 904,
59675967
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt",
59685968
"source": "Tools running",
59695969
"surface": "android",
59705970
"id": "native.android.781f84dfaf7da9d6"
59715971
},
59725972
{
59735973
"kind": "ui-named-argument",
5974-
"line": 854,
5974+
"line": 906,
59755975
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt",
59765976
"source": "OpenClaw is working",
59775977
"surface": "android",
59785978
"id": "native.android.d851a32f367f8b31"
59795979
},
59805980
{
59815981
"kind": "ui-named-argument",
5982-
"line": 857,
5982+
"line": 909,
59835983
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt",
59845984
"source": "+${toolCalls.size - 4} more",
59855985
"surface": "android",
59865986
"id": "native.android.0fd6b75cadc0ce75"
59875987
},
59885988
{
59895989
"kind": "ui-named-argument",
5990-
"line": 867,
5990+
"line": 919,
59915991
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt",
59925992
"source": "Thinking",
59935993
"surface": "android",
59945994
"id": "native.android.7e0aea1dca378135"
59955995
},
59965996
{
59975997
"kind": "ui-named-argument",
5998-
"line": 868,
5998+
"line": 920,
59995999
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt",
60006000
"source": "OpenClaw is preparing a response.",
60016001
"surface": "android",
60026002
"id": "native.android.98a0d4d5bba788c4"
60036003
},
60046004
{
60056005
"kind": "ui-named-argument",
6006-
"line": 987,
6006+
"line": 1054,
60076007
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt",
60086008
"source": "Stop",
60096009
"surface": "android",
60106010
"id": "native.android.76d574acfac94fee"
60116011
},
60126012
{
60136013
"kind": "ui-named-argument",
6014-
"line": 1004,
6014+
"line": 1120,
6015+
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt",
6016+
"source": "Default",
6017+
"surface": "android",
6018+
"id": "native.android.2cb3ec7379426dfe"
6019+
},
6020+
{
6021+
"kind": "conditional-branch",
6022+
"line": 1186,
6023+
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt",
6024+
"source": "Pin model",
6025+
"surface": "android",
6026+
"id": "native.android.f8d0f6ba7608abc3"
6027+
},
6028+
{
6029+
"kind": "conditional-branch",
6030+
"line": 1186,
6031+
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt",
6032+
"source": "Unpin model",
6033+
"surface": "android",
6034+
"id": "native.android.09a13ed8f039a9c3"
6035+
},
6036+
{
6037+
"kind": "ui-named-argument",
6038+
"line": 1203,
60156039
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt",
60166040
"source": "No commands found",
60176041
"surface": "android",
60186042
"id": "native.android.5953c956ff208e6e"
60196043
},
60206044
{
60216045
"kind": "ui-named-argument",
6022-
"line": 1066,
6046+
"line": 1265,
60236047
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt",
60246048
"source": "Gateway offline",
60256049
"surface": "android",
60266050
"id": "native.android.8e3e367df24cae4b"
60276051
},
60286052
{
60296053
"kind": "ui-named-argument",
6030-
"line": 1156,
6054+
"line": 1355,
60316055
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt",
60326056
"source": "Attach image",
60336057
"surface": "android",
60346058
"id": "native.android.623e434c83e3c020"
60356059
},
60366060
{
60376061
"kind": "ui-named-argument",
6038-
"line": 1171,
6062+
"line": 1370,
60396063
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt",
60406064
"source": "Message OpenClaw",
60416065
"surface": "android",
60426066
"id": "native.android.f1d69eb66c5dfa39"
60436067
},
60446068
{
60456069
"kind": "ui-named-argument",
6046-
"line": 1186,
6070+
"line": 1385,
60476071
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt",
60486072
"source": "Voice",
60496073
"surface": "android",
60506074
"id": "native.android.19396391033f4fa8"
60516075
},
60526076
{
60536077
"kind": "ui-named-argument",
6054-
"line": 1224,
6078+
"line": 1423,
60556079
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt",
60566080
"source": "Remove attachment",
60576081
"surface": "android",
60586082
"id": "native.android.5054269049758d6a"
60596083
},
60606084
{
60616085
"kind": "conditional-branch",
6062-
"line": 1245,
6086+
"line": 1444,
60636087
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt",
60646088
"source": "Main",
60656089
"surface": "android",
60666090
"id": "native.android.5fa853a957713a56"
60676091
},
60686092
{
60696093
"kind": "ui-named-argument",
6070-
"line": 1301,
6094+
"line": 1500,
60716095
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt",
60726096
"source": "Send",
60736097
"surface": "android",
60746098
"id": "native.android.6e2fcc9d67fc1273"
60756099
},
60766100
{
60776101
"kind": "conditional-branch",
6078-
"line": 1340,
6102+
"line": 1539,
60796103
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt",
60806104
"source": "$contextLabel · ${contextMeterThinkingLabel(thinkingLevel)}",
60816105
"surface": "android",

apps/android/app/src/main/java/ai/openclaw/app/MainViewModel.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ class MainViewModel(
141141
val modelAuthProviders: StateFlow<List<GatewayModelProviderSummary>> = runtimeState(initial = emptyList()) { it.modelAuthProviders }
142142
val modelCatalogRefreshing: StateFlow<Boolean> = runtimeState(initial = false) { it.modelCatalogRefreshing }
143143
val modelCatalogErrorText: StateFlow<String?> = runtimeState(initial = null) { it.modelCatalogErrorText }
144+
val modelFavorites: StateFlow<List<String>> = prefs.modelFavorites
145+
val modelRecents: StateFlow<List<String>> = prefs.modelRecents
144146
val talkSetupReadiness: StateFlow<GatewayTalkSetupReadiness> =
145147
runtimeState(initial = GatewayTalkSetupReadiness.unverified()) { it.talkSetupReadiness }
146148
val gatewayDefaultAgentId: StateFlow<String?> = runtimeState(initial = null) { it.gatewayDefaultAgentId }
@@ -220,6 +222,7 @@ class MainViewModel(
220222
val chatError: StateFlow<String?> = runtimeState(initial = null) { it.chatError }
221223
val chatHealthOk: StateFlow<Boolean> = runtimeState(initial = false) { it.chatHealthOk }
222224
val chatThinkingLevel: StateFlow<String> = runtimeState(initial = "off") { it.chatThinkingLevel }
225+
val chatSelectedModelRef: StateFlow<String?> = runtimeState(initial = null) { it.chatSelectedModelRef }
223226
val chatStreamingAssistantText: StateFlow<String?> = runtimeState(initial = null) { it.chatStreamingAssistantText }
224227
val chatPendingToolCalls: StateFlow<List<ChatPendingToolCall>> = runtimeState(initial = emptyList()) { it.chatPendingToolCalls }
225228
val chatSessions: StateFlow<List<ChatSessionEntry>> = runtimeState(initial = emptyList()) { it.chatSessions }
@@ -666,6 +669,17 @@ class MainViewModel(
666669
ensureRuntime().setChatThinkingLevel(level)
667670
}
668671

672+
fun setChatSessionModel(
673+
sessionKey: String,
674+
modelRef: String?,
675+
) {
676+
ensureRuntime().setChatSessionModel(sessionKey = sessionKey, modelRef = modelRef)
677+
}
678+
679+
fun toggleModelFavorite(ref: String) {
680+
prefs.toggleModelFavorite(ref)
681+
}
682+
669683
fun switchChatSession(sessionKey: String) {
670684
ensureRuntime().switchChatSession(sessionKey)
671685
}

apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -939,6 +939,7 @@ class NodeRuntime private constructor(
939939
transcriptCache = chatTranscriptCache,
940940
cacheScope = ::chatCacheScope,
941941
commandOutbox = chatCommandOutbox,
942+
recordModelRecent = prefs::recordModelRecent,
942943
).also {
943944
it.applyMainSessionKey(_mainSessionKey.value)
944945
}
@@ -1441,6 +1442,7 @@ class NodeRuntime private constructor(
14411442
val chatError: StateFlow<String?> = chat.errorText
14421443
val chatHealthOk: StateFlow<Boolean> = chat.healthOk
14431444
val chatThinkingLevel: StateFlow<String> = chat.thinkingLevel
1445+
val chatSelectedModelRef: StateFlow<String?> = chat.selectedModelRef
14441446
val chatStreamingAssistantText: StateFlow<String?> = chat.streamingAssistantText
14451447
val chatPendingToolCalls: StateFlow<List<ChatPendingToolCall>> = chat.pendingToolCalls
14461448
val chatSessions: StateFlow<List<ChatSessionEntry>> = chat.sessions
@@ -2690,6 +2692,13 @@ class NodeRuntime private constructor(
26902692
chat.setThinkingLevel(level)
26912693
}
26922694

2695+
fun setChatSessionModel(
2696+
sessionKey: String,
2697+
modelRef: String?,
2698+
) {
2699+
chat.setSessionModel(sessionKey = sessionKey, modelRef = modelRef)
2700+
}
2701+
26932702
fun switchChatSession(sessionKey: String) {
26942703
chat.switchSession(sessionKey)
26952704
}

0 commit comments

Comments
 (0)