Skip to content

Commit fac0e9e

Browse files
committed
fix the chat loading behavior
1 parent 404f2bc commit fac0e9e

6 files changed

Lines changed: 31 additions & 63 deletions

File tree

firebase-ai/app/src/main/java/com/google/firebase/quickstart/ai/feature/text/AudioSummarizationViewModel.kt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,8 @@ class AudioSummarizationViewModel : ChatViewModel() {
3030
}
3131
)
3232

33-
_uiState.value = ChatUiState.Success(
34-
messages = chatHistory.map { UiChatMessage(it) },
35-
attachments = emptyList()
36-
)
33+
_messages.value = chatHistory.map { UiChatMessage(it) }
34+
_uiState.value = ChatUiState.Success
3735

3836
val generativeModel = Firebase.ai.generativeModel(
3937
modelName = "gemini-2.5-flash"

firebase-ai/app/src/main/java/com/google/firebase/quickstart/ai/feature/text/ChatViewModel.kt

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,15 @@ import kotlinx.coroutines.launch
1717
@OptIn(PublicPreviewAPI::class)
1818
abstract class ChatViewModel : ViewModel() {
1919

20-
protected val _uiState: MutableStateFlow<ChatUiState> =
21-
MutableStateFlow(
22-
ChatUiState.Success(
23-
messages = emptyList(),
24-
attachments = emptyList()
25-
))
20+
protected val _uiState = MutableStateFlow<ChatUiState>(ChatUiState.Success)
2621
val uiState: StateFlow<ChatUiState> = _uiState.asStateFlow()
2722

23+
protected val _messages = MutableStateFlow<List<UiChatMessage>>(emptyList())
24+
val messages: StateFlow<List<UiChatMessage>> = _messages.asStateFlow()
25+
26+
protected val _attachments = MutableStateFlow<List<Attachment>>(emptyList())
27+
val attachments: StateFlow<List<Attachment>> = _attachments.asStateFlow()
28+
2829
abstract val initialPrompt: String
2930

3031
// Builder for the next message
@@ -35,20 +36,16 @@ abstract class ChatViewModel : ViewModel() {
3536
* Handles adding the message to the UI and setting the loading state.
3637
*/
3738
fun sendMessage(userMessage: String) {
38-
val uiStateValue = _uiState.value
39-
if (uiStateValue !is ChatUiState.Success) return
40-
4139
val prompt = contentBuilder
4240
.text(userMessage)
4341
.build()
4442

45-
val updatedMessages = uiStateValue.messages + UiChatMessage(prompt)
46-
_uiState.value = uiStateValue.copy(messages = updatedMessages)
43+
_messages.value = _messages.value + UiChatMessage(prompt)
4744

4845
viewModelScope.launch {
4946
_uiState.value = ChatUiState.Loading
5047
try {
51-
performSendMessage(prompt, updatedMessages)
48+
performSendMessage(prompt, _messages.value)
5249
} catch (e: Exception) {
5350
_uiState.value = ChatUiState.Error(e.localizedMessage ?: "Unknown error")
5451
} finally {
@@ -83,10 +80,9 @@ abstract class ChatViewModel : ViewModel() {
8380
"Could not display the response because it was missing required attribution components."
8481
)
8582
} else {
86-
_uiState.value = ChatUiState.Success(
87-
messages = currentMessages + UiChatMessage(candidate.content, candidate.groundingMetadata),
88-
attachments = emptyList()
89-
)
83+
_messages.value = currentMessages + UiChatMessage(candidate.content, candidate.groundingMetadata)
84+
_attachments.value = emptyList()
85+
_uiState.value = ChatUiState.Success
9086
}
9187
}
9288

@@ -95,19 +91,14 @@ abstract class ChatViewModel : ViewModel() {
9591
mimeType: String?,
9692
fileName: String? = "Unnamed file"
9793
) {
98-
val uiStateValue = _uiState.value
99-
if (uiStateValue !is ChatUiState.Success) return
100-
10194
if (mimeType?.contains("image") == true) {
10295
// images should be attached as ImageParts
10396
contentBuilder.image(decodeBitmapFromImage(fileInBytes))
10497
} else {
10598
contentBuilder.inlineData(fileInBytes, mimeType ?: "text/plain")
10699
}
107-
108-
_uiState.value = uiStateValue.copy(
109-
attachments = uiStateValue.attachments + Attachment(fileName ?: "Unnamed file")
110-
)
100+
101+
_attachments.value = _attachments.value + Attachment(fileName ?: "Unnamed file")
111102
}
112103

113104
protected fun decodeBitmapFromImage(input: ByteArray) =

firebase-ai/app/src/main/java/com/google/firebase/quickstart/ai/feature/text/TravelTipsViewModel.kt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,8 @@ class TravelTipsViewModel : ChatViewModel() {
5959
}
6060
))
6161

62-
_uiState.value = ChatUiState.Success(
63-
messages = chat.history.map { UiChatMessage(it) },
64-
attachments = emptyList()
65-
)
62+
_messages.value = chat.history.map { UiChatMessage(it) }
63+
_uiState.value = ChatUiState.Success
6664
}
6765

6866
override suspend fun performSendMessage(prompt: Content, currentMessages: List<UiChatMessage>) {

firebase-ai/app/src/main/java/com/google/firebase/quickstart/ai/feature/text/VideoSummarizationViewModel.kt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,8 @@ class VideoSummarizationViewModel : ChatViewModel() {
3232
}
3333
)
3434

35-
_uiState.value = ChatUiState.Success(
36-
messages = chatHistory.map { UiChatMessage(it) },
37-
attachments = emptyList()
38-
)
35+
_messages.value = chatHistory.map { UiChatMessage(it) }
36+
_uiState.value = ChatUiState.Success
3937

4038
val generativeModel = Firebase.ai.generativeModel(
4139
modelName = "gemini-2.5-flash"

firebase-ai/app/src/main/java/com/google/firebase/quickstart/ai/ui/ChatScreen.kt

Lines changed: 10 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ fun ChatScreen(
8787
chatViewModel: ChatViewModel
8888
) {
8989
val uiState by chatViewModel.uiState.collectAsStateWithLifecycle()
90+
val messages by chatViewModel.messages.collectAsStateWithLifecycle()
91+
val attachments by chatViewModel.attachments.collectAsStateWithLifecycle()
9092

9193
val initialPrompt: String = chatViewModel.initialPrompt
9294

@@ -97,27 +99,13 @@ fun ChatScreen(
9799
modifier = Modifier
98100
.fillMaxSize()
99101
) {
100-
when (val state = uiState) {
101-
is ChatUiState.Success -> {
102-
ChatList(
103-
state.messages,
104-
listState,
105-
modifier = Modifier
106-
.fillMaxSize()
107-
.weight(0.5f)
108-
)
109-
}
110-
is ChatUiState.Loading -> {
111-
// Box(modifier = Modifier.weight(0.5f).fillMaxSize(), contentAlignment = Alignment.Center) {
112-
// LinearProgressIndicator()
113-
// }
114-
}
115-
is ChatUiState.Error -> {
116-
Box(modifier = Modifier.weight(0.5f).fillMaxSize(), contentAlignment = Alignment.Center) {
117-
Text(text = state.message, color = MaterialTheme.colorScheme.error)
118-
}
119-
}
120-
}
102+
ChatList(
103+
messages,
104+
listState,
105+
modifier = Modifier
106+
.fillMaxSize()
107+
.weight(0.5f)
108+
)
121109

122110
Box(
123111
contentAlignment = Alignment.BottomCenter
@@ -148,9 +136,7 @@ fun ChatScreen(
148136
)
149137
}
150138
}
151-
(uiState as? ChatUiState.Success)?.let {
152-
AttachmentsList(it.attachments)
153-
}
139+
AttachmentsList(attachments)
154140
val context = LocalContext.current
155141
val contentResolver = context.contentResolver
156142
MessageInput(

firebase-ai/app/src/main/java/com/google/firebase/quickstart/ai/ui/ChatUiState.kt

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,6 @@ data class UiChatMessage(
2222

2323
sealed interface ChatUiState {
2424
data object Loading : ChatUiState
25-
data class Success(
26-
val messages: List<UiChatMessage> = emptyList(),
27-
val attachments: List<Attachment> = emptyList(),
28-
) : ChatUiState
25+
data object Success : ChatUiState
2926
data class Error(val message: String) : ChatUiState
3027
}

0 commit comments

Comments
 (0)