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 fourth assignment, we'll have you implement lots of the UI/VM logic underlying a relatively complex, totally-AI-powered rating system for your photos! As many app ideas out there start using permissions and libraries to access features on your phone such as photos and the camera, this app will feature a photo picker!
The overall idea is that users will be able to upload their photos into this app's gallery, and get a vibe rating for each photo they upload.
Let's walk through the code, shall we?
Release Code:
Expand each of the files below for a description of the release code!
PhotoRatingRepository.kt
This Model class provides mock networking/local storage functions that allow you to get photos by their stored ID, rate their vibes on 5 different scales, and save new images.
Here's a breakdown of the functions you'll use:
getImageFromId(): Given an [id], returns the image associated with it.
getImageIds(): Returns a list of all image IDs.
happinessRating(), virtueRating(), anxietyRating(), excitementRating(), sadnessRating() : Computes and returns a Float rating for the image associated with the input id. This is actually a pretty expensive computation, so it may take a while.
saveImage(): Saves a new image to "local storage."
UIEvent.kt
This is the UIEvent class discussed in lecture.
ImageCard.kt
A general-use component that displays an image that is either loading or loaded.
If the image input is null, the image is considered still loading.
If the image input is a proper bitmap (image array data), the image renders.
UploadImageCard.kt
A similar card to the above that instead displays a little indicator the user can press to, allegedly, upload a new image.
RatingLabel.kt
A bit of animated text with a label and a (loading) score that displays the rating/score of a particular emotion:
There are some other files, but those should be self-explanatory or redundant--the important ones will be referenced in the Requirements.
Requirements:
This assignment is also roughly split into "features."
(expand each of your features' requirements below!)
1) Rendering Photos
While we've provided a good amount of VM-M starter code, the images we've loaded in the home screen still aren't rendering.
Connect the images to the UI so that the UI renders an ImageCard for each image in the UiState.
Make sure the modifier here renders the image reasonably, still with 220.dp height.
You should see the following (we added one test image automatically):
2) Uploading Photos
Currently, nothing happens if you press on the Upload Image card! Let's implement the ability for the user to upload a new image, and have that image show up!
Add a new HomeViewModel function that fires when the user clicks the upload card.
Implement the above function such that a UIEvent is sent to the home screen.
Consume the event in the home screen, launching the photo picker. You can use the following snippet:
When the user successfully picks a photo, send that bitmap back to the VM! We've implemented the code that will automatically make this image show up if you've implemented (1-4) correctly.
See the completed demo for how images should pop up! (Don't worry about the fact that all images reload. That's our fault.)
3) Navigation
Currently, clicking on an ImageCard does nothing. Implement our card so we end up with navigation to the rating screen!
Add an onClick to ImageCard that is tied to the surrounding Surface.
When an ImageCard is clicked, navigate with the given navController to the rating screen, passing in the image ID as argument.
(NOTE: you can use uiState.ids to help with this purpose)
Tweak the existing onLoadImage() such that after the user uploads an image, they will also undergo this navigation 1s later, after refreshImages() is called.
HINT: you will need to use a UIEvent; navController exists only in the UI. You will also need to call delay(1000).
Again, see the demo to see what to expect!
4) Rating Nav Args
Let's switch gears over to the rating screen!
val id: String = checkNotNull(savedStateHandle["id"])
Note this line in RatingViewModel. This pulls the image ID nav arg given to the rating screen. Don't worry too much about how this works; just know savedStateHandle is used to pull navigation arguments via some Hilt/Lifecycle shenanigans.
Write an init block (this fires when the screen first opens) that loads the image and sends it down as a bitmap to the screen. You may reference examples in HomeViewModel for how to do this, especially with coroutines (like viewModelScope.launch).
Adjust RatingScreen.kt such that this new bitmap info is correctly sent to its ImageCard.
Make it so that the button "See my Rating!" is only enabled if the image bitmap is non-null.
You should see the image pop up after you are done! Note that you'll have to write your own UIState class and a few other things; we've intentionally kept this view model very bare bones as starter code.
Your image should now render (after it has loaded):
5) Show the Ratings!
Finally, let's make it so that the user can indeed see their ratings! This implementation is a bit more open-ended, but please reference the demo video to see what we generally expect! Don't worry about making the UI exactly match.
After the user presses "See my Rating!", replace the footer to instead animate out and show 5 rating labels.
Please use the colors we've given you: Happiness, Excitement, etc.!
As part of the UiState, load the ratings using photoRatingRepository and send them down through the screen, through the footer, to these labels.
If you've solved A5 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 A5!