Leave a rating/review
OK, you’re nearing the end of the course, but I’ve got one more challenge for you. It’s focused primarily on adding some look and feel options to the FaveFlicks app with an @ObservableObject, but it also requires you to add some new @State properties, a new modal view, and to build a little user interface - things you should know well after viewing the course so far!
For the challenge: add a new look and feel setting sheet to the app that allows you to change the accent color and symbol shape for the ratings view.
Look for the TODO’s in the project comments for some hints if you get stuck. Go ahead and give this a try, then check back here when you’re done for my solution.
OK, here’s the starter project. Let’s go to the LookAndFeelStore first, since that will drive everything you want to add.
- Add a new class, making sure it implements ObservableObject
- Add a @Published property that initializes a default value for the LookAndFeelInfo
class LookAndFeelStore: ObservableObject {
@Published var currentLookAndFeelInfo = LookAndFeelInfo(accentColor: Color.blue, symbolName: "star")
}
Let’s define that LookAndFeelInfo struct
- Create a new struct called LookAndFeelInfo
- Add a property for the accent color
- Add a property for the symbol name
- Don’t forget to import Combine since you’re using ObservableObject, and also SwiftUI since you’re using Color
struct LookAndFeelInfo {
let accentColor: Color
let symbolName: String
}
Next go to LookAndFeelView to update the view and hook it into the store.
- Add an @ObservedObject for the store
- Add state properties for the accent color and symbolname
@ObservedObject var lookAndFeelStore: LookAndFeelStore
@State private var accentColor = Color.red
@State private var symbolName = ""
And then pass in the bindings to the ColorPicker and Picker below.
- Add an onAppear modifier to load the UI state from the store
.onAppear {
accentColor = lookAndFeelStore.currentLookAndFeelInfo.accentColor
symbolName = lookAndFeelStore.currentLookAndFeelInfo.symbolName
}
- Fill in the updateLookAndFeelInfo function to set the store state based on the UI state
func updateLookAndFeelInfo() {
let newLookAndFeelInfo = LookAndFeelInfo(accentColor: accentColor, symbolName: symbolName)
lookAndFeelStore.currentLookAndFeelInfo = newLookAndFeelInfo
}
Don’t forget to update the preview struct so everything compiles.
With those in place, go to the RatingView
- Add an @ObservedObject for the LookAndFeelStore
@ObservedObject var lookAndFeelStore: LookAndFeelStore
- Then replace “star” in the symbol name with the symbolName property from the store
\(lookAndFeelStore.currentLookAndFeelInfo.symbolName)
- Then update the previews struct so things compile (in this file at least)
RatingView(lookAndFeelStore: LookAndFeelStore(), rating: 4.5)
OK, getting there but still some compile errors. Let’s make our way towards the MovieList, starting with AddMovie.
- The RatingView needs an additional argument for the look and feel store, so add that
RatingView(lookAndFeelStore: lookAndFeelStore, rating: rating)
- Add that property as an @ObservedObject to the top of the struct
@ObservedObject var lookAndFeelStore: LookAndFeelStore
Go to MovieRow next to do a similar update for RatingsView
RatingView(lookAndFeelStore: lookAndFeelStore, rating: rating)
- and include that property as before
@ObservedObject var lookAndFeelStore: LookAndFeelStore
Now with those in place, open up MovieList.swift. Starting from the top
- Add an @ObservedObject for the look and feel store, as well as a State object to handle the presentation of the look and feel view sheet
@ObservedObject var lookAndFeelStore = LookAndFeelStore()
Then update various elements in the body
- Update the call to MovieRow and AddRow to include the lookAndFeelStore argument
- Add the sheet modifier to display the look and feel view
- Add a new button to the trailing section of the navigation bar, putting both buttons in an HStack
- Add an accentColor modifier to the NavigationView, and pass in the accent color from the LookAndFeelStore
var body: some View {
NavigationView {
List {
ForEach(movieStore.movies, id: \.title) {
MovieRow(movie: $0, 🟢lookAndFeelStore: lookAndFeelStore)
}
}
.sheet(isPresented: $isPresented) {
AddMovie(movieStore: movieStore, showModal: $isPresented, lookAndFeelStore: lookAndFeelStore)
}
🟢.sheet(isPresented: $isLookAndFeelPresented) {
LookAndFeelView(lookAndFeelStore: lookAndFeelStore)
}
.navigationBarTitle(Text("Fave Flicks"))
.navigationBarItems(
leading:
NavigationLink(destination: UserView(userStore: userStore)) {
HStack {
Text(userStore.currentUserInfo.userName)
Image(systemName: "person.fill")
}
},
trailing:
🟢HStack {
🟢Button(action: { isLookAndFeelPresented.toggle() }) {
Image(systemName: "gear")
}
Button(action: { isPresented.toggle() }) {
Image(systemName: "plus")
}
}
)
}
🟢.accentColor(lookAndFeelStore.currentLookAndFeelInfo.accentColor)
}
}
Reload MovieList in the live preview, and try out the new functionality, changing the accent color and the shape of the Rating symbol.
Great job!