Module 2 Wrap Up Challenge Assistance Request

Hello everyone! I’ve been wracking my brain over this one and figure it’s time to reach out for some help. Now, I have two problems preventing me from completing this:

  1. MAJOR: I cannot for the life of me figure out how to call the information of variable watched when each button is pressed to pull the information of either ‘watched’ or ‘!watched’. When I create an action and assign () → Void, I get all sorts of errors and it just overwhelms me on where everything goes.; and
  2. MINOR: My rating star page isn’t setup correctly. Currently, I am using IF statements to draw between two rating scales. It’s ugly, and I don’t like it, so any help in getting this one buttoned up would be greatly appreciated.

DataService.swift

import Foundation

struct DataService {
    
    func getData() -> [MovieInfo] {
        //button code to pull watched array set
        return [
            MovieInfo(movieTitle: "Lawrence of Arabia", movieYear: "1962", movieDirector: "David Lean", movieDescription: "An epic historical drama that follows the life of T.E. Lawrence during World War I.", watched: false, movieRating: 4),
            MovieInfo(movieTitle: "Gone with the Wind", movieYear: "1939", movieDirector: "Victor Fleming", movieDescription: "A timeless epic set during the American Civil War, known for its memorable characters and sweeping romance.", watched: false, movieRating: 4),
            MovieInfo(movieTitle: "The Godfather", movieYear: "1982", movieDirector: "Francis Ford Coppola", movieDescription: "A crime drama that explores the Italian-American Mafia, featuring Marlon Brando and Al Pacino.", watched: false, movieRating: 4),
            MovieInfo(movieTitle: "Casablanca", movieYear: "1942", movieDirector: "Michael Curtiz", movieDescription: "A romantic drama set in World War II, starring Humphrey Bogart and Ingrid Bergman.", watched: false, movieRating: 4),
            MovieInfo(movieTitle: "Citizen Kane", movieYear: "1941", movieDirector: "Orson Welles", movieDescription: "Often cited as one of the greatest films ever made, it tells the story of a newspaper magnate's rise and fall.", watched: false, movieRating: 4),
            MovieInfo(movieTitle: "Schindler's List", movieYear: "1993", movieDirector: "Steven Spielberg", movieDescription: "A powerful portrayal of a German businessman who saved the lives of more than a thousand Polish-Jewish refugees during the Holocaust.", watched: true,  movieRating: 5),
            MovieInfo(movieTitle: "The Shawshank Redemption", movieYear: "1994", movieDirector: "David Lean", movieDescription: "A prison drama based on a Stephen King novella, known for its powerful storytelling.", watched: true, movieRating: 5),
            MovieInfo(movieTitle: "Star Wars: Episode IV - A New Hope", movieYear: "1977", movieDirector: "George Lucas", movieDescription: "The original Star Wars film launched one of the most iconic franchises in cinematic history.", watched: true, movieRating: 5),
            MovieInfo(movieTitle: "The Wizard of Oz", movieYear: "1939", movieDirector: "Victor Fleming", movieDescription: "A beloved musical fantasy film that has captivated audiences for generations.", watched: true, movieRating: 4),
            MovieInfo(movieTitle: "Pulp Fiction", movieYear: "1994", movieDirector: "Quentin Tarantino", movieDescription: "A non-linear crime film with an ensemble cast and innovative storytelling.", watched: true, movieRating: 5)
        ]
    }
}

MovieInfo.swift

import Foundation

struct MovieInfo: Identifiable {
    var id: UUID = UUID()
    var movieTitle: String
    var movieYear: String
    var movieDirector: String
    var movieDescription: String
    var watched: Bool
    var movieRating: Int
}

CustomButton.swift

import SwiftUI

struct CustomButton: View {
    
    var buttonText: String
    var dataService = DataService()
    
    var body: some View {
        
        Button{
        //Try to figure out how to get an action for multiple buttons from one instance
        }label: {
            Text(buttonText)
        }
        .padding(15)
        .border(.blue, width: 1)
    }
}

#Preview {
    CustomButton(buttonText: "Sample Button")
}

RatingStars.swift

import SwiftUI

struct RatingStars: View {
    var rating: Int
    
    var body: some View {
        HStack {
            if rating == 4{
                Image(systemName: "star.fill")
                Image(systemName: "star.fill")
                Image(systemName: "star.fill")
                Image(systemName: "star.fill")
            } else if rating == 5 {
                Image(systemName: "star.fill")
                Image(systemName: "star.fill")
                Image(systemName: "star.fill")
                Image(systemName: "star.fill")
                Image(systemName: "star.fill")
            }
        }
        .font(.caption)
        .foregroundColor(.yellow)

    }
}

#Preview {
    RatingStars(rating: 5)
}

Movies.swift

import SwiftUI

struct Movies: View {
    @State var movieInfo: [MovieInfo] = [MovieInfo]()
    var dataService = DataService()
    
    
    var body: some View {
        VStack {
            //MOVIE LIST//
                List(movieInfo) { movie in
                    MovieListRow(movie: movie)
                }
                .listStyle(.plain)
                .onAppear {
                    movieInfo = dataService.getData()               }
            HStack {
                //BUTTONS//
                Spacer()
                CustomButton(buttonText: "Movies to Watch")
                Spacer()
                CustomButton(buttonText: "Movies Watched")
                Spacer()
            }
            
        }
    }
}

#Preview {
    Movies()
}

GtiHub repo:

@KreachR

Hi Brandon,

Welcome to the community.

This is a tough challenge but the difficult coding part related to passing a closure to the Custom button is provided by Chris Ching in the challenge description. So if you create your button something like this:

struct CustomButton: View {
    
    var buttonText: String
//    var dataService = DataService()
    var action: () -> Void

    var body: some View {
        
        Button(action: action, label: {
            Text(buttonText)
        })
        .padding(15)
        .border(.blue, width: 1)
    }
}

and then at the call site in the Movies View, depending on whether you want to show the ones that have been watched or those that have not been watched, you can make uses of a filter to select the right group of records.

CustomButton(buttonText: "Movies to Watch", action: {
    movieInfo = dataService.getData().filter { $0.watched == false } 
})

If that filter code does not make any sense to you then let me know and I will try to expand on it so that hopefully you get it.

If you wanted to make the code inside the Movies View a little less cluttered then what you could do is create two separate functions inside DataService, one to retrieve those watched and the other to retrieve those not watched. For example, the function to retrieve those that have been watched could be something like this:

func watched() -> [MovieInfo] {
    return getData().filter { $0.watched == true }
}

Then in your CustomButton you would say:

CustomButton(buttonText: "Movies to Watch", action: {
    movieInfo = dataService.watched()
})

The star rating is a little tricky but look at it from the point of view of being a maximum of 5 stars and what you can do is create a loop using a ForEach with a defined range from 0 to <5. If the passed in rating is less than the current loop value then that can be a star.fill otherwise it’s a star.

Hope that provides some help.

Thank you so much for taking the time to reply Chris, I really appreciate it. One major problem that is preventing me from moving forward is in the preview section of the CustomButton view:

#Preview {
    CustomButton(buttonText: "", buttonAction: () -> Void)
}

I’m really not sure what to pass in here. Anything I put returns an error or doesn’t allow the preview or build to complete. Any thoughts?

Change that to this:

#Preview {
    CustomButton(buttonText: "", buttonAction: {} )
}

What that does is pass in an empty closure.

How awesome! Got it to work! I was missing the empty closure. Also, was able to figure out the ForEach with (1…rating) which perfectly assesses my rating variable and then passes that many stars in. THANK YOU! I was wracking my brain over this for 3 days. You’re a lifesaver!

1 Like