Skip to content
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

Add Circuit logic to AI Bot #955

Merged
merged 11 commits into from
Sep 16, 2024
Merged

Add Circuit logic to AI Bot #955

merged 11 commits into from
Sep 16, 2024

Conversation

kateliu20
Copy link
Contributor

@kateliu20 kateliu20 commented Sep 10, 2024

Adding Circuit logic, which has a Chat Screen state, UI (ChatWindowUi object) and Presenter which handles the sending logic. I followed the tutorial and Project Gen for reference, but I also haven't used Circuit before, so I would appreciate any feedback.

f27ddc1

@kateliu20 kateliu20 marked this pull request as ready for review September 10, 2024 15:07
Comment on lines 37 to 41
val circuit =
Circuit.Builder()
.addPresenter<ChatScreen, ChatScreen.State>(ChatPresenter())
.addUi<ChatScreen, ChatScreen.State> { state, modifier -> ChatWindow(state, modifier) }
.build()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you should wrap this in a remember { } block, otherwise it'll get recreated every time

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

f27ddc1 under ChatPanel.kt

Comment on lines 34 to 38
val newMessage = Message(event.message, isMe = true)
messages = messages + newMessage
val response = Message(callApi(event.message), isMe = false)
messages = messages + response
currentInput = "" // clear chat after sending
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this is just stubbed out, but for future ref you don't wanna have too much logic in this even callback directly. Instead, you generally want it to just update internal state.

Comment on lines 34 to 38
val newMessage = Message(event.message, isMe = true)
messages = messages + newMessage
val response = Message(callApi(event.message), isMe = false)
messages = messages + response
currentInput = "" // clear chat after sending
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest keeping "currentInput" entirely in the UI, and just use this event to signal a new sent message with the text received from the UI. What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this makes sense, I should just keep it in UI. Will make this change! Thanks

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed it in f27ddc1 under ChatPresenter.kt

sealed class Event : CircuitUiEvent {
data class SendMessage(val message: String) : Event()

data class UpdateInput(val input: String) : Event()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this do?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought since SendMessage is an event, then I should be using CircuitUiEvent with a sealed class. That's how I set it up for the ChatPresenter. But after I removed currentInput from the presenter, I don't need that UpdateInput class.

Comment on lines 62 to 64
object ChatWindowUi {
@Composable
fun ChatWindow(state: ChatScreen.State, modifier: Modifier = Modifier) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally we just keep these functions top-level, no need for the wrapper object

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

f27ddc1 in ChatWindowUi.kt

}

@Composable
fun ConversationField(modifier: Modifier = Modifier, onSendMessage: (String) -> Unit) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: private should be the default


import androidx.compose.runtime.Immutable

// not sure if I need this in a separate class
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you expand on this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think it's okay to have the Message data class in a separate file? Or is it unnecessary?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you're going to reuse it yeah, otherwise you could just co-locate it with the rest of your state models

Comment on lines 131 to 132
keyboardActions = KeyboardActions.Default,
maxLines = Int.MAX_VALUE,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean to leave these defaults in?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did initially because I was trying different things for the "shift+enter" functionality. I just realized that it doesn't make a difference, so I will remove it. Thanks for pointing it out!

Icon(
painter = painterResource("/drawable/send.svg"),
contentDescription = "Send",
modifier = Modifier.size(20.dp),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this I would recommend using Modifier.minimumInteractiveComponentSize(), which is more dynamic and will respect user accessibility settings too

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this be compatible while using Jewel, since this is with Material?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Maybe look at their docs and see if they have anything comparable?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could I use wrapContentSize() and set unbounded = true to account for accessibility?

According to the docs:
"Allow the content to measure at its desired size without regard for the incoming measurement minimum width or minimum height constraints, and, if unbounded is true, also without regard for the incoming maximum constraints. If the content's measured size is smaller than the minimum size constraint, align it within that minimum sized space. If the content's measured size is larger than the maximum size constraint (only possible when unbounded is true), align within the maximum space."

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not exactly. For example - a vector can be scaled to any size so it may not have an intrinsic size to be wrapped. I would try the jewel or intellij platform docs first, I assume there are some standard sizes for IJ iconography/buttons

@kateliu20 kateliu20 added this pull request to the merge queue Sep 16, 2024
Merged via the queue into main with commit 7b2b6a4 Sep 16, 2024
3 checks passed
@kateliu20 kateliu20 deleted the kl_circuit_aibot branch September 16, 2024 19:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants