This assignment has a release code! Please download it below, extract it, and open it in Android Studio. Ensure it can compile and run fine on your emulator before starting this assignment.
For our third assignment, we'll have you implement the ViewModel to connect up a mock chat app! Instead of chatting with another real person (as that would require a lot of real, complex networking), we'll have you chat with a mini pocket philosopher on your phone!
We've had enough assignments about money at this point, haven't we? And money isn't happiness, after all...
Let's walk through the code, shall we?
Release Code:
Expand each of the files below for a description of the release code!
ChatRepository.kt
A Model class that performs (mock) networking tasks to implement that chatbot/chat functionality.
DO NOT EDIT THIS FILE.
You may interface with this file, though, using the following properties, to complete (mock) networking:
chatMessageFlow: A flow emitting a list of (all) the chat messages in the history of the chat.
currentlyTypingFlow: A flow emitting (as a Boolean) whether the chatbot is "typing" or not.
botNameFlow: A flow emitting the name of the chat bot.
sendMessage(text: String): A mock networking function that will send the user's text message as a chat message.
ChatViewModel.kt
A (Hilt) ViewModel class that connects up ChatRepository.kt and ChatScreen.kt.
You'll mostly be working in this file for your solution. This file is VERY incomplete.
For starters though, we've given you...
uiStateFlow: The (only) state flow that your VM should use to emit state down to the UI. Emits an object of type ChatUiState.
ChatUiState: A data class representing the UI state that contains ALL the data that ChatScreen.kt needs to know. This class is currently incomplete; you'll need to add fields here as you go.
ChatScreen.kt
The primary (and only) UI screen in this assignment. It consists of a header, a body consisting of chat messages in a big LazyColumn, and a footer where the user can type in a message and send.
For organization, this file consists of several @Composables:
ChatScreen(): The main screen Composable.
ChatFooter(): The footer, where the text field and send button lay.
ChatHeader(): The header, where the chat bot's name and last sent text lay.
There happens to be a @Preview here for the header; take a look if you'd like!
There are a few other files here, but those are not too important and are mostly complete:
ChatBubble.kt is just a component for the Chat Bubble.
Other files are basically junk; don't worry about them.
Requirements:
Okay, onto the assignment!
This assignment is a bit different from previous assignments in that you'll be implementing features, one by one. The reason we do not split then into files is because your solution will often have to span several files for each feature.
(expand each of your features' requirements below!)
1) Reading the Message Flow
First, let's connect our chat up with our pocket philosopher! It wants to say some stuff to us right now, but we can't quite hear it just yet until we connect our VM to our Model repository!
Inject an instance of ChatRepository.kt into our ViewModel.
Read the flow value of the chat messages flow from the repository, using it to update (with a copy) the current Ui State Flow with the correct messages!
For this section, we've already hooked up the messages field from the UiState to the UI. So this should be all you need to do!
Note: If you've done this correctly, you should no longer see the initial test messages, and should now see the following chat:
Seems like our philosopher is trying to reach us! Let's finish the next parts so we can have a nice, deep chat :-)
2) Typing into the Text Field
If you currently try typing into the text field in the footer, nothing changes, and the text currently freezes at "TODO". Let's fix this!
Add a new field to ChatUiState corresponding to the text currently typed into the text field.
Pipeline this down the the UI such that the UI now reads from this text and puts it through the ChatFooter() into the BasicTextField value.
Now time for the reverse direction! Add a new function onTextChanged(text: String) to your VM. Make it so that when you type text and the BasicTextField value changes, this VM method is called!
Hints:
You'll need to add new arguments to ChatFooter()!
Ideally, 2 new arguments: one for the text downwards, and one for the onTextChanged upwards!
You should now be able to type a message into the box. But you can't quite send it yet...
3) Sending a Message
Now let's allow ourselves to actually send a message to our philosopher!
Change the derived field value isSendEnabled such that if the typed text (field in your ChatUiState from part 2) is non empty, it is true, otherwise false.
If you've done this correctly, the Send button should now turn enabled if you've typed in text!
Add an onSend() that gets called by the Button onClick in ChatFooter. You'll need to pipeline this onClick upwards, similar to what you did in part 2.
Implement onSend() :
Send the (typed in) message by calling chatRepository.sendMessage(...) .
Clear the typed in message after the message is sent.
You should now be able to send a message and see your philosopher respond! In fact, you should actually be able to converse with your philosopher now. Try it out!
4) Reading the Header Flow Information
Okay, nearly there! But the name we've given our philosopher isn't quite showing up top! And our chat isn't keeping track of when our last message was sent... let's fix that!
Similarly to previous parts, hook up ChatRepository's botNameFlow down through the Repository, to the VM, to the UI, so that the TODO text now reads the bot's name!
It should be ??? at first, then populate with your name you've given after you give the philosopher a name.
Do the same for timestampFlow such that the "Last message sent at: TODO" now reads the correct time!
(A lot of working with MVVM is going through these motions. After this, we just have one more and you'll be an expert!)
Here's an example of what you should see after you name your philosopher:
5) Reading the Currently Typing Flow
Finally for a finishing touch! Your philosopher often pauses and takes time to think, but also takes time to type out a response! It'd be great if you could have a little indicator for that...
Thankfully, your UI already has this! See the TODO for part 5) in ChatScreen?
Read from currentlyTypingFlow from the chat repository (down through the VM, to the UI) to put the correct boolean condition for if the philosopher is typing (instead of just currently FALSE).
If you've solved A4 correctly, your solution should look something like this...
When you're done, export your project through Android Studio and upload your ZIP to CMS! Congrats on finishing A4!
Note: Perhaps you find it annoying that you have to scroll with each message manually? We'll learn a solution for that next week with UIEvents!